2199 lines
90 KiB
JavaScript
2199 lines
90 KiB
JavaScript
/* jshint -W097 */
|
|
/* jshint strict:true */
|
|
/* jslint vars: true */
|
|
/* global io:false */
|
|
/* global jQuery:false */
|
|
/* jslint browser:true */
|
|
/* jshint browser:true */
|
|
/* global _ */
|
|
/* global ace */
|
|
/* global console */
|
|
/* global alert */
|
|
/* global confirm */
|
|
/* global systemLang: true */
|
|
/* global license */
|
|
/* global translateAll */
|
|
/* global initGridLanguage */
|
|
'use strict';
|
|
|
|
//if (typeof Worker === 'undefined') alert('your browser does not support WebWorkers :-(');
|
|
|
|
Array.prototype.remove = function () {
|
|
var what;
|
|
var a = arguments;
|
|
var L = a.length;
|
|
var ax;
|
|
while (L && this.length) {
|
|
what = a[--L];
|
|
while ((ax = this.indexOf(what)) !== -1) {
|
|
this.splice(ax, 1);
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
// for IE
|
|
if (!console.debug) {
|
|
console.debug = console.log;
|
|
}
|
|
if (typeof Number === 'undefined') {
|
|
console.log('define Number');
|
|
Number = function (obj) {
|
|
return parseFloat(obj);
|
|
}
|
|
}
|
|
if (!Object.assign) {
|
|
Object.assign = $.extend;
|
|
}
|
|
|
|
|
|
var $iframeDialog = null; // used in adapter settings window
|
|
var configNotSaved = null; // used in adapter settings window
|
|
var showConfig = null; // used in adapter settings window
|
|
var defaults = {};
|
|
var customPostInits = {};
|
|
var FORBIDDEN_CHARS = /[\]\[*,;'"`<>\\\s?]/g;
|
|
|
|
// used in adapter settings window
|
|
var adapterRedirect = function (redirect, timeout) {
|
|
if (redirect) {
|
|
setTimeout(function () {
|
|
redirect += document.location.pathname;
|
|
redirect += document.location.hash;
|
|
document.location.href = redirect;
|
|
}, timeout || 5000);
|
|
}
|
|
};
|
|
var gMain = null; // for google maps
|
|
|
|
function detectIE() {
|
|
var ua = window.navigator.userAgent;
|
|
|
|
var msie = ua.indexOf('MSIE ');
|
|
if (msie > 0) {
|
|
// IE 10 or older => return version number
|
|
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
|
|
}
|
|
|
|
var trident = ua.indexOf('Trident/');
|
|
if (trident > 0) {
|
|
// IE 11 => return version number
|
|
var rv = ua.indexOf('rv:');
|
|
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
|
|
}
|
|
|
|
var edge = ua.indexOf('Edge/');
|
|
if (edge > 0) {
|
|
// Edge (IE 12+) => return version number
|
|
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
|
|
}
|
|
|
|
// other browser
|
|
return false;
|
|
}
|
|
|
|
(function ($) {
|
|
$(document).ready(function () {
|
|
var path = location.pathname + 'socket.io';
|
|
if (location.pathname.match(/^\/admin\//)) {
|
|
path = '/socket.io';
|
|
}
|
|
|
|
var allTabs = {};
|
|
|
|
var main = {
|
|
objects: {},
|
|
states: {},
|
|
currentHost: '',
|
|
currentTab: null,
|
|
currentDialog: null,
|
|
currentUser: '',
|
|
subscribesStates: {},
|
|
subscribesObjects: {},
|
|
subscribesLogs: 0,
|
|
socket: io.connect('/', {path: path}),
|
|
systemConfig: null,
|
|
instances: null,
|
|
objectsLoaded: false,
|
|
waitForRestart: false,
|
|
tabs: null,
|
|
dialogs: {},
|
|
selectId: null,
|
|
config: {},
|
|
ignoreJSupdate: false, // set to true after some global script updated and till system.adapter.javascript.x updated
|
|
addEventMessage: function (id, stateOrObj, isMessage, isState) {
|
|
// cannot directly use tabs.events.add, because to init time not available.
|
|
tabs.events.add(id, stateOrObj, isMessage, isState);
|
|
},
|
|
saveConfig: function (attr, value) {
|
|
if (attr) main.config[attr] = value;
|
|
|
|
if (typeof storage !== 'undefined') {
|
|
storage.set('adminConfig', JSON.stringify(main.config));
|
|
}
|
|
},
|
|
saveTabs: function () {
|
|
this.socket.emit ('setObject', 'system.config', this.systemConfig, function (err) {
|
|
if (err) {
|
|
this.showError (err);
|
|
}
|
|
})
|
|
},
|
|
|
|
// Helper methods
|
|
upToDate: function (_new, old) {
|
|
_new = _new.split('.');
|
|
old = old.split('.');
|
|
_new[0] = parseInt(_new[0], 10);
|
|
old[0] = parseInt(old[0], 10);
|
|
if (_new[0] > old[0]) {
|
|
return false;
|
|
} else if (_new[0] === old[0]) {
|
|
_new[1] = parseInt(_new[1], 10);
|
|
old[1] = parseInt(old[1], 10);
|
|
if (_new[1] > old[1]) {
|
|
return false;
|
|
} else if (_new[1] === old[1]) {
|
|
_new[2] = parseInt(_new[2], 10);
|
|
old[2] = parseInt(old[2], 10);
|
|
return (_new[2] <= old[2]);
|
|
} else {
|
|
return true;
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
},
|
|
|
|
// Methods
|
|
cmdExec: function (host, cmd, callback) {
|
|
host = host || main.currentHost;
|
|
$stdout.val('');
|
|
|
|
$dialogCommand.modal('open');
|
|
|
|
stdout = '$ ./yunkong2 ' + cmd;
|
|
$dialogCommand.data('finished', false).find('.btn').html(_('In background'));
|
|
$dialogCommand.find('.command').html(stdout);
|
|
$dialogCommand.find('.progress-dont-close').removeClass('disabled');
|
|
$adminSideMain.find('.button-command').removeClass('error').addClass('in-progress');
|
|
$dialogCommand.data('max', null);
|
|
$dialogCommand.data('error', '');
|
|
$dialogCommandProgress.addClass('indeterminate').removeClass('determinate');
|
|
|
|
if (cmd.match(/^upload /)) {
|
|
$dialogCommand.find('.progress-text').html(_('Upload started...')).removeClass('error');
|
|
} else if (cmd.match(/^del [-_\w\d]+\.[\d]+$/)) {
|
|
$dialogCommand.find('.progress-text').html(_('Removing of instance...')).removeClass('error');
|
|
} else if (cmd.match(/^del /)) {
|
|
$dialogCommand.find('.progress-text').html(_('Removing of adapter...')).removeClass('error');
|
|
} else if (cmd.match(/^url /)) {
|
|
$dialogCommand.find('.progress-text').html(_('Install or update from URL...')).removeClass('error');
|
|
} else if (cmd.match(/^add /)) {
|
|
$dialogCommand.find('.progress-text').html(_('Add instance...')).removeClass('error');
|
|
} else{
|
|
$dialogCommand.find('.progress-text').html(_('Started...')).removeClass('error');
|
|
}
|
|
|
|
$stdout.val(stdout);
|
|
// generate the unique id to coordinate the outputs
|
|
activeCmdId = Math.floor(Math.random() * 0xFFFFFFE) + 1;
|
|
cmdCallback = callback;
|
|
main.socket.emit('cmdExec', host, activeCmdId, cmd, function (err) {
|
|
if (err) {
|
|
stdout += '\n' + _(err);
|
|
$stdout.val(stdout);
|
|
cmdCallback = null;
|
|
callback(err);
|
|
} else {
|
|
if (callback) callback();
|
|
}
|
|
});
|
|
},
|
|
confirmMessage: function (message, title, icon, buttons, callback) {
|
|
// if standard buttons
|
|
if (typeof buttons === 'function') {
|
|
callback = buttons;
|
|
$dialogConfirm.find('.modal-footer').html(
|
|
'<a class="modal-action modal-close waves-effect waves-green btn-flat translate" data-result="true">' + _('Ok') + '</a>' +
|
|
'<a class="modal-action modal-close waves-effect waves-green btn-flat translate">' + _('Cancel') + '</a>');
|
|
$dialogConfirm.find('.modal-footer .modal-action').on('click', function () {
|
|
var cb = $dialogConfirm.data('callback');
|
|
cb && cb($(this).data('result'));
|
|
});
|
|
} else if (typeof buttons === 'object') {
|
|
var tButtons = '';
|
|
for (var b = buttons.length - 1; b >= 0; b--) {
|
|
tButtons += '<a class="modal-action modal-close waves-effect waves-green btn-flat translate" data-id="' + b + '">' + buttons[b] + '</a>';
|
|
}
|
|
$dialogConfirm.find('.modal-footer').html(tButtons);
|
|
$dialogConfirm.find('.modal-footer .modal-action').on('click', function () {
|
|
var cb = $dialogConfirm.data('callback');
|
|
cb && cb($(this).data('id'));
|
|
});
|
|
}
|
|
|
|
$dialogConfirm.find('.dialog-title').text(title || _('Please confirm'));
|
|
if (icon) {
|
|
$dialogConfirm.find('.dialog-icon')
|
|
.show()
|
|
.html(icon);
|
|
} else {
|
|
$dialogConfirm.find('.dialog-icon').hide();
|
|
}
|
|
$dialogConfirm.find('.dialog-text').html(message);
|
|
$dialogConfirm.data('callback', callback);
|
|
$dialogConfirm.modal('open');
|
|
},
|
|
showMessage: function (message, title, icon) {
|
|
$dialogMessage.find('.dialog-title').text(title || _('Message'));
|
|
if (icon) {
|
|
$dialogMessage.find('.dialog-icon')
|
|
.show()
|
|
.html(icon);
|
|
} else {
|
|
$dialogMessage.find('.dialog-icon').hide();
|
|
}
|
|
$dialogMessage.find('.dialog-text').html(message);
|
|
$dialogMessage.modal('open');
|
|
},
|
|
showError: function (error) {
|
|
main.showMessage(_(error), _('Error'), 'error_outline');
|
|
},
|
|
showToast: function (parent, message, icon, duration, isError, classes) {
|
|
if (parent && parent instanceof jQuery) {
|
|
parent = parent[0];
|
|
}
|
|
classes = classes || [];
|
|
|
|
if (typeof classes === 'string') {
|
|
classes = [classes];
|
|
}
|
|
isError && classes.push('dropZone-error');
|
|
|
|
M.toast({
|
|
parentSelector: parent || $('body')[0],
|
|
html: message + (icon ? '<i class="material-icons">' + icon + '</i>' : ''),
|
|
displayLength: duration || 3000,
|
|
classes: classes
|
|
});
|
|
},
|
|
formatDate: function (dateObj, justTime) {
|
|
//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 = typeof dateObj;
|
|
if (text === 'string') {
|
|
if (justTime) {
|
|
return dateObj.substring(8);
|
|
} else {
|
|
return dateObj;
|
|
}
|
|
}
|
|
// if less 2000.01.01 00:00:00
|
|
if (text !== 'object') dateObj = dateObj < 946681200000 ? new Date(dateObj * 1000) : new Date(dateObj);
|
|
|
|
var v;
|
|
if (!justTime) {
|
|
text = dateObj.getFullYear();
|
|
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;
|
|
}
|
|
} else {
|
|
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;
|
|
},
|
|
/*initSelectId: function () {
|
|
if (main.selectId) return main.selectId;
|
|
main.selectId = $('#dialog-select-member').selectId('init', {
|
|
objects: main.objects,
|
|
states: main.states,
|
|
filter: {type: 'state'},
|
|
name: 'admin-select-member',
|
|
texts: {
|
|
select: _('Select'),
|
|
cancel: _('Cancel'),
|
|
all: _('All'),
|
|
id: _('ID'),
|
|
name: _('Name'),
|
|
role: _('Role'),
|
|
room: _('Room'),
|
|
value: _('Value'),
|
|
selectid: _('Select ID'),
|
|
from: _('From'),
|
|
lc: _('Last changed'),
|
|
ts: _('Time stamp'),
|
|
wait: _('Processing...'),
|
|
ack: _('Acknowledged')
|
|
},
|
|
columns: ['image', 'name', 'role', 'room', 'value']
|
|
});
|
|
return main.selectId;
|
|
},*/
|
|
updateWizard: function () {
|
|
var $wizard = $('#button-wizard');
|
|
if (main.objects['system.adapter.discovery.0']) {
|
|
if (!$wizard.data('inited')) {
|
|
$wizard.data('inited', true);
|
|
$wizard/*.button({
|
|
icons: {primary: ' ui-icon-search'},
|
|
text: false
|
|
})*/.on('click', function () {
|
|
// open configuration dialog
|
|
main.navigate({
|
|
tab: 'instances',
|
|
dialog: 'config',
|
|
params: 'system.adapter.discovery.0'
|
|
});
|
|
}).attr('title', _('Device discovery'));
|
|
}
|
|
$wizard.show();
|
|
|
|
// Show wizard dialog
|
|
if (!main.systemConfig.common.wizard && main.systemConfig.common.licenseConfirmed) {
|
|
$wizard.trigger('click');
|
|
}
|
|
} else {
|
|
$wizard.hide();
|
|
}
|
|
},
|
|
getUser: function () {
|
|
if (!main.currentUser) {
|
|
main.socket.emit('authEnabled', function (auth, user) {
|
|
main.currentUser = 'system.user.' + user;
|
|
if (!auth) {
|
|
$('#button-logout').remove();
|
|
} else {
|
|
main._lastTimer = (new Date()).getTime();
|
|
monitor();
|
|
}
|
|
});
|
|
} else if (main.objects[main.currentUser]) {
|
|
var obj = main.objects[main.currentUser];
|
|
var name = '';
|
|
if (!obj || !obj.common || !obj.common.name) {
|
|
name = main.currentUser.replace(/^system\.user\./);
|
|
name = name[0].toUpperCase() + name.substring(1).toLowerCase();
|
|
} else {
|
|
name = translateName(obj.common.name);
|
|
}
|
|
if (obj && obj.common && obj.common.icon) {
|
|
var objs = {};
|
|
objs[main.currentUser] = obj;
|
|
$('#current-user-icon').html(main.getIcon(main.currentUser, null, objs));
|
|
} else {
|
|
$('#current-user-icon').html('<i class="large material-icons">account_circle</i>');
|
|
}
|
|
$('#current-user').html(name);
|
|
var groups = [];
|
|
for (var i = 0; i < tabs.users.groups.length; i++) {
|
|
var group = main.objects[tabs.users.groups[i]];
|
|
if (group && group.common && group.common.members && group.common.members.indexOf(main.currentUser) !== -1) {
|
|
groups.push(_(translateName(group.common.name)));
|
|
}
|
|
}
|
|
$('#current-group').html(groups.join(', '));
|
|
}
|
|
},
|
|
|
|
// Delete objects
|
|
_delObject: function (idOrList, callback) {
|
|
var id;
|
|
if (!Array.isArray(idOrList)) {
|
|
if (typeof idOrList !== 'string') return callback && callback('invalid idOrList parameter');
|
|
idOrList = [idOrList];
|
|
}
|
|
|
|
function doIt() {
|
|
if (idOrList.length === 0) {
|
|
return callback && setTimeout(callback, 0, null, id);
|
|
}
|
|
id = idOrList.pop();
|
|
if (main.objects[id] && main.objects[id].common && (main.objects[id].common['object-non-deletable'] || main.objects[id].common.dontDelete)) {
|
|
main.showMessage (_ ('Cannot delete "%s" because not allowed', id), '', 'notifications');
|
|
setTimeout(doIt, 0);
|
|
} else {
|
|
var obj = main.objects[id];
|
|
main.socket.emit('delObject', id, function (err) {
|
|
if (err && err !== 'Not exists') {
|
|
main.showError (err);
|
|
return callback(err);
|
|
}
|
|
if (obj && obj.type === 'state') {
|
|
main.socket.emit ('delState', id, function (err) {
|
|
if (err && err !== 'Not exists') {
|
|
main.showError (err);
|
|
return callback(err);
|
|
}
|
|
setTimeout(doIt, 0);
|
|
});
|
|
} else {
|
|
setTimeout(doIt, 0);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
doIt();
|
|
},
|
|
/*_delObject_old: function (idOrList, callback) {*
|
|
var id;
|
|
if (typeof idOrList === 'object') {
|
|
if (!idOrList || !idOrList.length) {
|
|
if (callback) callback(null);
|
|
return;
|
|
}
|
|
id = idOrList.pop();
|
|
} else {
|
|
id = idOrList;
|
|
}
|
|
|
|
if (main.objects[id] && main.objects[id].common && (main.objects[id].common['object-non-deletable'] || main.objects[id].common.dontDelete)) {
|
|
main.showMessage(_('Cannot delete "%s" because not allowed', id), '', 'notice');
|
|
if (typeof idOrList === 'object') {
|
|
setTimeout(function () {
|
|
this._delObject(idOrList, callback);
|
|
}.bind(this), 0);
|
|
} else {
|
|
if (callback) {
|
|
setTimeout(function () {
|
|
callback(null, idOrList);
|
|
}, 0);
|
|
}
|
|
}
|
|
} else {
|
|
var obj = main.objects[id];
|
|
main.socket.emit('delObject', id, function (err) {
|
|
if (err && err !=='Not exists') {
|
|
main.showError(err);
|
|
return;
|
|
}
|
|
if (obj && obj.type === 'state') {
|
|
main.socket.emit('delState', id, function (err) {
|
|
if (err && err !=='Not exists') {
|
|
main.showError(err);
|
|
return;
|
|
}
|
|
if (typeof idOrList === 'object') {
|
|
setTimeout(function () {
|
|
this._delObject(idOrList, callback);
|
|
}.bind(this), 0);
|
|
} else {
|
|
if (callback) {
|
|
setTimeout(function () {
|
|
callback(null, idOrList);
|
|
}, 0);
|
|
}
|
|
}
|
|
}.bind(this));
|
|
} else {
|
|
if (typeof idOrList === 'object') {
|
|
setTimeout(function () {
|
|
this._delObject(idOrList, callback);
|
|
}.bind(this), 0);
|
|
} else {
|
|
if (callback) {
|
|
setTimeout(function () {
|
|
callback(null, idOrList);
|
|
}, 0);
|
|
}
|
|
}
|
|
}
|
|
}.bind(this));
|
|
}
|
|
},*/
|
|
_delObjects: function (rootId, isAll, callback) {
|
|
if (!isAll) {
|
|
this._delObject(rootId, callback);
|
|
} else {
|
|
var list = [];
|
|
for (var id in main.objects) {
|
|
if (main.objects.hasOwnProperty(id) && id.substring(0, rootId.length + 1) === rootId + '.') {
|
|
list.push(id);
|
|
}
|
|
}
|
|
list.push(rootId);
|
|
list.sort();
|
|
|
|
this._delObject(list, function () {
|
|
if (callback) callback();
|
|
});
|
|
}
|
|
},
|
|
delObject: function ($tree, id, callback) {
|
|
var leaf = $tree ? $tree.selectId('getTreeInfo', id) : null;
|
|
if (main.objects[id]) {
|
|
if (leaf && leaf.children) {
|
|
// ask if only object must be deleted or just this one
|
|
main.confirmMessage(_('Do you want to delete just <span style="color: blue">one object</span> or <span style="color: red">all</span> children of %s too?', id), null, 'help_outline', [_('_All'), _('Only one'), _('Cancel')], function (result) {
|
|
// If all
|
|
if (result === 0) {
|
|
main._delObjects(id, true, callback);
|
|
} else
|
|
// if only one object
|
|
if (result === 1) {
|
|
main._delObjects(id, false, callback);
|
|
} // else do nothing
|
|
});
|
|
} else {
|
|
main.confirmMessage(_('Are you sure to delete %s?', id), null, 'help_outline', function (result) {
|
|
// If all
|
|
if (result) main._delObjects(id, true, callback);
|
|
});
|
|
}
|
|
} else if (leaf && leaf.children) {
|
|
main.confirmMessage(_('Are you sure to delete all children of %s?', id), null, 'help_outline', function (result) {
|
|
// If all
|
|
if (result) main._delObjects(id, true, callback);
|
|
});
|
|
} else {
|
|
main.showMessage(_('Object "<b>%s</b>" does not exists. Update the page.', id), _('Error'), 'help_outline', function (result) {
|
|
// If all
|
|
if (result) main._delObjects(id, true, callback);
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
gMain = main; // for google maps
|
|
|
|
var tabs = {
|
|
hosts: new Hosts(main), // must be first to read the list of hosts
|
|
objects: new Objects(main),
|
|
adapters: new Adapters(main),
|
|
instances: new Instances(main),
|
|
users: new Users(main),
|
|
//groups: new Groups(main),
|
|
enums: new Enums(main),
|
|
events: new Events(main),
|
|
logs: new Logs(main),
|
|
states: null,
|
|
intro: new Intro(main)
|
|
};
|
|
|
|
if (typeof States !== 'undefined') {
|
|
tabs.states = new States(main);
|
|
}
|
|
|
|
main.instances = tabs.instances.list;
|
|
main.tabs = tabs;
|
|
main.dialogs = {
|
|
system: new System(main),
|
|
customs: new Customs(main),
|
|
config: new Config(main),
|
|
editobject: new EditObject(main),
|
|
issue: new Issue(main),
|
|
readme: new Readme(main)
|
|
};
|
|
|
|
var stdout;
|
|
var cmdCallback = null;
|
|
var activeCmdId = null;
|
|
var $stdout = $('#stdout');
|
|
|
|
var $dialogCommand = $('#dialog-command');
|
|
var $dialogLicense = $('#dialog-license-main');
|
|
var $dialogMessage = $('#dialog-message');
|
|
var $dialogConfirm = $('#dialog-confirm');
|
|
var $dialogCommandProgress = $dialogCommand.find('.progress div');
|
|
|
|
var $adminSideMenu = $('#admin_sidemenu_menu');
|
|
var $adminSideMain = $('#admin_sidemenu_main');
|
|
|
|
var firstConnect = true;
|
|
|
|
// detect touch devices
|
|
if (!('ontouchstart' in window || navigator.maxTouchPoints)) {
|
|
$('body').addClass('desktop-screen');
|
|
}
|
|
if (navigator.userAgent.indexOf('Safari') !== -1 &&
|
|
navigator.userAgent.indexOf('Chrome') === -1 &&
|
|
navigator.userAgent.indexOf('Android') === -1) {
|
|
$('body').addClass('safari');
|
|
main.browser = 'safari';
|
|
main.noSelect = true;
|
|
} else if (detectIE()) {
|
|
$('body').addClass('ie');
|
|
// workaround
|
|
main.browser = 'ie';
|
|
main.browserVersion = detectIE();
|
|
main.noSelect = true;
|
|
$('#host-adapters-btn').css('margin-top', '10px');
|
|
}
|
|
|
|
// Read all positions, selected widgets for every view,
|
|
// Selected view, selected menu page,
|
|
// Selected widget or view page
|
|
// Selected filter
|
|
if (typeof storage !== 'undefined') {
|
|
try {
|
|
main.config = storage.get('adminConfig');
|
|
if (main.config) {
|
|
main.config = JSON.parse(main.config);
|
|
} else {
|
|
main.config = {};
|
|
}
|
|
} catch (e) {
|
|
console.log('Cannot load edit config');
|
|
main.config = {};
|
|
}
|
|
}
|
|
|
|
function globalClickHandler(event){
|
|
$('#admin_sidemenu_dialog').html('');
|
|
$('html').off('click', globalClickHandler);
|
|
}
|
|
|
|
function initHtmlButtons() {
|
|
main.socket.emit('getVersion', function (err, version) {
|
|
var $versionBtn = $('.button-version');
|
|
if (!$versionBtn.hasClass('vendor')) {
|
|
$versionBtn.text('yunkong2.admin ' + version);
|
|
}
|
|
});
|
|
|
|
$('.choose-tabs-config-button').off('click').on('click', function(event) {
|
|
var $dialog = $('#admin_sidemenu_dialog');
|
|
var html = $dialog.html();
|
|
if (html) {
|
|
$dialog.html('');
|
|
// disable global handler
|
|
$('html').off('click', globalClickHandler);
|
|
return;
|
|
}
|
|
setTimeout(function () {
|
|
// enable global handler
|
|
$('html').on('click', globalClickHandler);
|
|
}, 100);
|
|
var $e = $(event.target);
|
|
var offs = $e.offset();
|
|
offs.top += $e.height() - 2;
|
|
|
|
var text =
|
|
'<dialog open class="tab-selector m" style="top: ' + offs.top + 'px; left: ' + offs.left + 'px;">' + // style="overflow: visible; z-index: 999; ">'
|
|
'<div>' +
|
|
'<ul style="">';
|
|
|
|
var $lis = $adminSideMenu;
|
|
for (var tid in allTabs) {
|
|
var name = allTabs[tid];
|
|
var found = $adminSideMenu.find('.admin-sidemenu-items[data-tab="' + tid + '"]').length;
|
|
// TABS
|
|
/*$adminSideMenu.each(function (i, e) {
|
|
if (tid === $(e).attr('aria-controls')) {
|
|
found = $(e);
|
|
return false;
|
|
}
|
|
});*/
|
|
var id = 'chk-' + tid;
|
|
text +=
|
|
'<li><input ' + (found ? 'checked' : 'unchecked') + ' class="chk-tab filled-in" type="checkbox" id="' + id + '" />' +
|
|
'<span for="' + id + '">' + _(name) + '</span></id>';
|
|
}
|
|
text += '' +
|
|
'</ul>' +
|
|
'</div>' +
|
|
'</dialog>';
|
|
$dialog.append(text);
|
|
|
|
$dialog.find('.chk-tab').off('change').on('change', function (event) {
|
|
var id = $(this).attr('id').substr(4);
|
|
if ($(this).prop('checked')) {
|
|
main.systemConfig.common.tabs.push(id);
|
|
} else {
|
|
var pos = main.systemConfig.common.tabs.indexOf(id);
|
|
if (id !== -1) {
|
|
main.systemConfig.common.tabs.splice(pos, 1);
|
|
}
|
|
}
|
|
main.saveTabs();
|
|
initTabs();
|
|
});
|
|
// workaround for materialize checkbox problem
|
|
$dialog.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');
|
|
}
|
|
});
|
|
});
|
|
|
|
main.updateWizard();
|
|
|
|
$('#button-logout').on('click', function () {
|
|
window.location.href = '/logout/';
|
|
});
|
|
|
|
window.onhashchange = function () {
|
|
main.navigateDo();
|
|
};
|
|
main.navigateDo();
|
|
}
|
|
|
|
function initHtmlTabs() {
|
|
// jQuery UI initializations
|
|
initSideNav();
|
|
|
|
if (!main.tabsInited) {
|
|
main.tabsInited = true;
|
|
|
|
initHtmlButtons();
|
|
|
|
$('#events_threshold').on('click', function () {
|
|
main.socket.emit('eventsThreshold', false);
|
|
});
|
|
} else {
|
|
var $menu = $adminSideMenu;
|
|
var panelSelector = $menu.data('problem-link');
|
|
if (panelSelector) {
|
|
var $panel = $(panelSelector);
|
|
// Init source for iframe
|
|
if ($panel.length) {
|
|
var link = $panel.data('src');
|
|
if (link && link.indexOf('%') === -1) {
|
|
var $iframe = $panel.find('iframe');
|
|
if ($iframe.length && !$iframe.attr('src')) {
|
|
$iframe.attr('src', link);
|
|
$menu.data('problem-link', null);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// show current tab
|
|
main.currentHash = null;
|
|
main.navigateDo();
|
|
}
|
|
}
|
|
|
|
function initTabs() {
|
|
// extract all additional instances
|
|
var text = '';
|
|
var list = [];
|
|
var addTabs = [];
|
|
|
|
allTabs = {};
|
|
for (var i = 0; i < main.instances.length; i++) {
|
|
var instance = main.instances[i];
|
|
var instanceObj = main.objects[instance];
|
|
if (!instanceObj.common || !instanceObj.common.adminTab) continue;
|
|
if (instanceObj.common.adminTab.singleton) {
|
|
var isFound = false;
|
|
var inst1 = instance.replace(/\.(\d+)$/, '.');
|
|
for (var j = 0; j < addTabs.length; j++) {
|
|
var inst2 = addTabs[j].replace(/\.(\d+)$/, '.');
|
|
if (inst1 === inst2) {
|
|
isFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!isFound) addTabs.push(instance);
|
|
} else {
|
|
addTabs.push(instance);
|
|
}
|
|
}
|
|
|
|
// Build the standard tabs together
|
|
$('.admin-tab').each(function () {
|
|
var $this = $(this);
|
|
var id = $this.attr('id');
|
|
list.push(id);
|
|
allTabs[id] = $this.data('name');
|
|
});
|
|
|
|
// Look for adapter tabs
|
|
for (var a = 0; a < addTabs.length; a++) {
|
|
var tab = main.objects[addTabs[a]];
|
|
var name = 'tab-' + tab.common.name;
|
|
|
|
var link = tab.common.adminTab.link || '/adapter/' + tab.common.name + '/tab.html';
|
|
if (tab.common.materializeTab) {
|
|
link = tab.common.adminTab.link || '/adapter/' + tab.common.name + '/tab_m.html';
|
|
}
|
|
|
|
var parts = addTabs[a].split('.');
|
|
var buttonName;
|
|
|
|
if (tab.common.adminTab.name) {
|
|
if (typeof tab.common.adminTab.name === 'object') {
|
|
if (tab.common.adminTab.name[systemLang]) {
|
|
buttonName = tab.common.adminTab.name[systemLang];
|
|
} else if (tab.common.adminTab.name.en) {
|
|
buttonName = _(tab.common.adminTab.name.en);
|
|
} else {
|
|
buttonName = _(tab.common.name);
|
|
}
|
|
} else {
|
|
buttonName = _(tab.common.adminTab.name);
|
|
}
|
|
} else {
|
|
buttonName = _(tab.common.name);
|
|
}
|
|
|
|
// if (main.objects[addTabs[a]].common.adminTab.name) {
|
|
// if (typeof main.objects[addTabs[a]].common.adminTab.name === 'object') {
|
|
// if (main.objects[addTabs[a]].common.adminTab.name[systemLang]) {
|
|
// buttonName = main.objects[addTabs[a]].common.adminTab.name[systemLang];
|
|
// } else if (main.objects[addTabs[a]].common.adminTab.name.en) {
|
|
// buttonName = _(main.objects[addTabs[a]].common.adminTab.name.en);
|
|
// } else {
|
|
// buttonName = _(main.objects[addTabs[a]].common.name);
|
|
// }
|
|
// } else {
|
|
// buttonName = _(main.objects[addTabs[a]].common.adminTab.name);
|
|
// }
|
|
// } else {
|
|
// buttonName = _(main.objects[addTabs[a]].common.name);
|
|
// }
|
|
|
|
if (!tab.common.adminTab.singleton) {
|
|
if (link.indexOf('?') !== -1) {
|
|
link += '&instance=' + parts[3];
|
|
} else {
|
|
link += '?instance=' + parts[3];
|
|
}
|
|
buttonName += '.' + parts[3];
|
|
name += '-' + parts[3];
|
|
} else {
|
|
parts[3] = 0;
|
|
}
|
|
|
|
list.push(name);
|
|
allTabs[name] = buttonName;
|
|
|
|
if (!main.systemConfig.common.tabs || main.systemConfig.common.tabs.indexOf(name) !==-1) {
|
|
var isReplace = false;
|
|
if (!link) {
|
|
link = '/adapter/' + parts[2] + '/tab.html';
|
|
if (tab.common.materilizeTab) {
|
|
link = '/adapter/' + parts[2] + '/tab_m.html';
|
|
}
|
|
} else {
|
|
// convert "http://%ip%:%port%" to "http://localhost:1880"
|
|
/*main.tabs.instances._replaceLinks(link, parts[2], parts[3], name, function (link, adapter, instance, arg) {
|
|
$('#' + arg).data('src', link);
|
|
});*/
|
|
isReplace = link.indexOf('%') !== -1;
|
|
}
|
|
|
|
text += '<li><a href="#' + name + '">' + buttonName + '</a></li>\n';
|
|
|
|
// noinspection JSJQueryEfficiency
|
|
if (!$('#' + name).length) {
|
|
var div = '<div id="' + name + '" data-name="' + buttonName + '" class="tab-custom ' + (isReplace ? 'link-replace' : '') + '" data-adapter="' + parts[2] + '" data-instance="' + parts[3] + '" data-src="' + link + '">' +
|
|
'<iframe class="iframe-in-tab" style="border: 0; solid #FFF; display: block; left: 0; top: 0; width: 100%; height: 100%"' +
|
|
'></iframe></div>';
|
|
$(div).hide().appendTo($('body'));
|
|
|
|
// TODO: temporary, until other tab will be adapted
|
|
$('#' + name).find ('.iframe-in-tab').on('load', function () {
|
|
var elem = $ (this).contents ().find('body>header');
|
|
if (!elem || !elem.length) elem = $(this).contents ().find('head');
|
|
if (elem && elem.length) elem.append('<link rel="stylesheet" type="text/css" href="../../lib/css/iob/selectID.css"/>');
|
|
});
|
|
} else {
|
|
$('#' + name).hide().appendTo($('body'));
|
|
}
|
|
} else {
|
|
$('#' + name).hide().appendTo($('body'));
|
|
}
|
|
}
|
|
$('.tab-custom').each(function () {
|
|
if (list.indexOf($(this).attr('id')) === -1) {
|
|
$('#' + $(this).attr('id')).remove();
|
|
}
|
|
});
|
|
|
|
if (!main.systemConfig.common.tabs) main.systemConfig.common.tabs = list;
|
|
|
|
if ($('.link-replace').length) {
|
|
var countLink = 0;
|
|
|
|
// If some objects cannot be read => go by timeout
|
|
var loadTimeout = setTimeout(function() {
|
|
loadTimeout = null;
|
|
initHtmlTabs(/*showTabs*/);
|
|
}, 100);
|
|
|
|
$('.link-replace').each(function () {
|
|
// convert "http://%ip%:%port%" to "http://localhost:1880"
|
|
countLink++;
|
|
main.tabs.instances._replaceLinks($(this).data('src'), $(this).data('adapter'), $(this).data('instance'), $(this).attr('id'), function (link, adapter, instance, arg) {
|
|
$('#' + arg).data('src', link).removeClass('link-replace');
|
|
if (!--countLink) {
|
|
if (loadTimeout) {
|
|
clearTimeout(loadTimeout);
|
|
loadTimeout = null;
|
|
initHtmlTabs(/*showTabs*/);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
} else {
|
|
initHtmlTabs();
|
|
}
|
|
}
|
|
|
|
main.initHostsList = function (isFirstInit) {
|
|
// fill the host list (select) on adapter tab
|
|
var $selHosts = $('#host-adapters');
|
|
if (isFirstInit && $selHosts.data('inited')) {
|
|
return
|
|
}
|
|
|
|
$selHosts.data('inited', true);
|
|
|
|
main.currentHost = main.currentHost || main.config.currentHost || '';
|
|
|
|
var lines = [];
|
|
var color;
|
|
var curId;
|
|
for (var i = 0; i < main.tabs.hosts.list.length; i++) {
|
|
lines.push('<li><a data-value="' + main.tabs.hosts.list[i].name + '">' + main.getHostIcon(main.objects[main.tabs.hosts.list[i].id], 'imgHost left') + main.tabs.hosts.list[i].name + '</a></li>');
|
|
if (!main.currentHost) {
|
|
main.currentHost = main.tabs.hosts.list[i].name;
|
|
}
|
|
if (main.currentHost === main.tabs.hosts.list[i].name) {
|
|
curId = main.tabs.hosts.list[i].id;
|
|
}
|
|
}
|
|
$selHosts.html(lines);
|
|
|
|
var $selBtn = $('#host-adapters-btn').show();
|
|
$selBtn
|
|
.text(_('Host:') + ' ' + main.currentHost)
|
|
.dropdown();
|
|
|
|
if (main.objects[curId] && main.objects[curId].common) {
|
|
color = main.objects[curId].common.color;
|
|
}
|
|
|
|
$selBtn.append($(main.getHostIcon(main.objects[curId], 'imgHost left')));
|
|
if (color) {
|
|
// set color of button
|
|
}
|
|
|
|
if (main.tabs.hosts.list.length < 2) {
|
|
$selBtn.addClass('disabled');
|
|
} else {
|
|
$selBtn.removeClass('disabled');
|
|
}
|
|
|
|
// host selector
|
|
$selHosts.find('a').on('click', function () {
|
|
var val = $(this).data('value');
|
|
var id = 'system.host.' + val + '.alive';
|
|
if (!main.states[id] || !main.states[id].val || main.states[id].val === 'null') {
|
|
main.showMessage(_('Host %s is offline', $(this).val()));
|
|
return;
|
|
}
|
|
|
|
main.currentHost = val;
|
|
|
|
$('#host-adapters-btn')
|
|
.text(_('Host:') + ' ' + main.currentHost)
|
|
.append($(this).find('.imgHost').clone());
|
|
// destroy current view and load anew
|
|
console.log(main.currentTab);
|
|
if (tabsInfo['tab-' + main.currentTab] && tabsInfo['tab-' + main.currentTab].host) {
|
|
// destroy actual tab
|
|
if (main.tabs[main.currentTab] && typeof main.tabs[main.currentTab].destroy === 'function') {
|
|
main.tabs[main.currentTab].destroy();
|
|
}
|
|
|
|
// init new tab
|
|
if (main.tabs[main.currentTab] && typeof main.tabs[main.currentTab].init === 'function') {
|
|
main.tabs[main.currentTab].init();
|
|
}
|
|
}
|
|
|
|
main.saveConfig('currentHost', main.currentHost);
|
|
});
|
|
};
|
|
|
|
// Use the function for this because it must be done after the language was read
|
|
function initAllDialogs() {
|
|
// todo delete it because jqgrid does not used any more
|
|
if (typeof initGridLanguage === 'function') {
|
|
initGridLanguage(main.systemConfig.common.language);
|
|
}
|
|
|
|
$dialogCommand.modal({
|
|
dismissible: false
|
|
});
|
|
$dialogMessage.modal();
|
|
$dialogConfirm.modal({
|
|
dismissible: false
|
|
});
|
|
|
|
$dialogCommand.find('.progress-show-more').off('change').on('change', function () {
|
|
var val = $(this).prop('checked');
|
|
main.saveConfig('progressMore', val);
|
|
if (val) {
|
|
$dialogCommand.find('.textarea').show();
|
|
} else {
|
|
$dialogCommand.find('.textarea').hide();
|
|
}
|
|
});
|
|
if (main.config.progressClose === undefined) {
|
|
main.config.progressClose = true;
|
|
}
|
|
$dialogCommand.find('.progress-dont-close input').on('change', function () {
|
|
main.saveConfig('progressClose', $(this).prop('checked'));
|
|
});
|
|
// workaround for materialize checkbox problem
|
|
$dialogCommand.find('input[type="checkbox"]+span').off('click').on('click', function () {
|
|
var $input = $(this).prev();
|
|
// ignore switch
|
|
if ($input.parent().parent().hasClass('switch')) return;
|
|
|
|
if (!$input.prop('disabled')) {
|
|
$input.prop('checked', !$input.prop('checked')).trigger('change');
|
|
}
|
|
});
|
|
$dialogCommand.find('.progress-dont-close input').prop('checked', main.config.progressClose);
|
|
$dialogCommand.find('.progress-show-more').prop('checked', !!main.config.progressMore).trigger('change');
|
|
$dialogCommand.find('.btn').on('click', function () {
|
|
if ($dialogCommand.data('finished')) {
|
|
$adminSideMain.find('.button-command').hide();
|
|
} else {
|
|
$adminSideMain.find('.button-command').show();
|
|
}
|
|
});
|
|
|
|
$adminSideMain.find('.button-command').on('click', function () {
|
|
$dialogCommand.modal('open');
|
|
});
|
|
}
|
|
|
|
function checkNodeJsVersions(hosts, index) {
|
|
index = index || 0;
|
|
if (hosts && index < hosts.length) {
|
|
main.socket.emit('sendToHost', hosts[index].name, 'getHostInfo', null, function (result) {
|
|
if (result && result['Node.js']) {
|
|
var major = parseInt(result['Node.js'].split('.').shift().replace('v', ''), 10);
|
|
if (major < 6 || major === 7 || major === 9 ) { // we allow 6, 8 and 10+
|
|
main.showMessage(_('This version of node.js "%s" on "%s" is deprecated. Please install node.js 6, 8 or newer', result['Node.js'], hosts[index].name), _('Suggestion'), 'error_outline');
|
|
}
|
|
}
|
|
setTimeout(function () {
|
|
checkNodeJsVersions(hosts, index + 1);
|
|
}, 100);
|
|
});
|
|
}
|
|
}
|
|
|
|
// ----------------------------- Objects show and Edit ------------------------------------------------
|
|
function getObjects(callback) {
|
|
main.socket.emit('getAllObjects', function (err, res) {
|
|
if (err) {
|
|
// following errors are possible
|
|
// permissionError
|
|
// Admin is not enabled in cloud settings!
|
|
window.alert(_(err));
|
|
return;
|
|
}
|
|
|
|
setTimeout(function () {
|
|
var obj;
|
|
main.objects = res;
|
|
for (var id in main.objects) {
|
|
if (!main.objects.hasOwnProperty(id) || id.slice(0, 7) === '_design') continue;
|
|
|
|
obj = main.objects[id];
|
|
|
|
if (obj.type === 'instance') main.instances.push(id);
|
|
if (obj.type === 'enum') tabs.enums.list.push(id);
|
|
if (obj.type === 'user') tabs.users.list.push(id);
|
|
if (obj.type === 'group') tabs.users.groups.push(id);
|
|
if (obj.type === 'adapter') tabs.adapters.list.push(id);
|
|
if (obj.type === 'host') tabs.hosts.addHost(obj);
|
|
|
|
// convert obj.history into obj.custom
|
|
if (obj.common && obj.common.history) {
|
|
obj.common.custom = JSON.parse(JSON.stringify(obj.common.history));
|
|
delete obj.common.history;
|
|
}
|
|
}
|
|
main.objectsLoaded = true;
|
|
main.initHostsList(true);
|
|
|
|
initTabs();
|
|
// init dialogs
|
|
for (var dialog in main.dialogs) {
|
|
if (main.dialogs.hasOwnProperty(dialog) && typeof main.dialogs[dialog].prepare === 'function') {
|
|
main.dialogs[dialog].prepare();
|
|
}
|
|
}
|
|
|
|
// Detect node.js version
|
|
checkNodeJsVersions(tabs.hosts.list);
|
|
|
|
main.getUser();
|
|
|
|
if (typeof callback === 'function') callback();
|
|
}, 0);
|
|
});
|
|
}
|
|
// ----------------------------- States show and Edit ------------------------------------------------
|
|
|
|
function getStates(callback) {
|
|
if (tabs.states) tabs.states.clear();
|
|
main.socket.emit('getStates', function (err, res) {
|
|
main.states = res;
|
|
if (typeof callback === 'function') {
|
|
setTimeout(function () {
|
|
callback();
|
|
}, 0);
|
|
}
|
|
});
|
|
}
|
|
|
|
function stateChange(id, state) {
|
|
id = id ? id.replace(/\s/g, '_') : '';
|
|
|
|
if (!id || !id.match(/\.messagebox$/)) {
|
|
if (tabs.states) {
|
|
tabs.states.stateChange(id, state);
|
|
}
|
|
tabs.objects.stateChange(id, state);
|
|
tabs.hosts.stateChange(id, state);
|
|
|
|
// Update alive and connected of main.instances
|
|
tabs.instances.stateChange(id, state);
|
|
tabs.adapters.stateChange(id, state);
|
|
main.dialogs.customs.stateChange(id, state);
|
|
|
|
if (main.selectId) {
|
|
main.selectId.selectId('state', id, state);
|
|
}
|
|
main.addEventMessage(id, state, false, true);
|
|
} else {
|
|
main.addEventMessage(id, state, true, true);
|
|
}
|
|
}
|
|
|
|
function objectChange(id, obj) {
|
|
//var changed = false;
|
|
//var oldObj = null;
|
|
var action = 'update';
|
|
|
|
// update main.objects cache
|
|
if (obj) {
|
|
if (obj._rev && main.objects[id]) main.objects[id]._rev = obj._rev;
|
|
if (!main.objects[id]) {
|
|
action = 'add';
|
|
}
|
|
if (action === 'add' || JSON.stringify(main.objects[id]) !== JSON.stringify(obj)) {
|
|
main.objects[id] = obj;
|
|
}
|
|
} else if (main.objects[id]) {
|
|
action = 'delete';
|
|
delete main.objects[id];
|
|
}
|
|
|
|
// update to event table
|
|
main.addEventMessage(id, obj, false, false);
|
|
|
|
tabs.objects.objectChange(id, obj, action);
|
|
|
|
main.selectId && main.selectId.selectId('object', id, obj, action);
|
|
|
|
tabs.enums.objectChange(id, obj, action);
|
|
tabs.intro.objectChange(id, obj, action);
|
|
|
|
// If system config updated
|
|
if (id === 'system.config') {
|
|
// Check language
|
|
if (main.systemConfig.common.language !== obj.common.language) {
|
|
window.location.reload();
|
|
}
|
|
|
|
main.systemConfig = obj;
|
|
initTabs();
|
|
}
|
|
|
|
if (id === 'system.adapter.discovery.0') {
|
|
main.updateWizard();
|
|
}
|
|
|
|
if (id.match(/^system\.host\.[-\w]+$/)) {
|
|
main.initHostsList();
|
|
}
|
|
|
|
tabs.instances.objectChange(id, obj, action);
|
|
|
|
if (id.match(/^script\.js\.global\..*/)) {
|
|
main.ignoreJSupdate = true;
|
|
}
|
|
|
|
if (obj && id.match(/^system\.adapter\.[\w-]+\.[0-9]+$/)) {
|
|
if (obj.common &&
|
|
obj.common.adminTab &&
|
|
!obj.common.adminTab.ignoreConfigUpdate
|
|
) {
|
|
// one exception for javascript. To able work with global scripts normally
|
|
if (!id.match(/^system\.adapter\.javascript\.[0-9]+$/) || !main.ignoreJSupdate) {
|
|
initTabs();
|
|
} else {
|
|
main.ignoreJSupdate = false;
|
|
}
|
|
}
|
|
|
|
if (obj && obj.type === 'instance' && obj.common.supportCustoms) {
|
|
// Update all states if customs enabled or disabled
|
|
tabs.objects.reinit();
|
|
}
|
|
}
|
|
|
|
tabs.hosts.objectChange(id, obj, action);
|
|
|
|
// Update users
|
|
tabs.users.objectChange(id, obj, action);
|
|
|
|
// update user in side menu
|
|
if (id === main.currentUser) {
|
|
main.getUser();
|
|
}
|
|
}
|
|
|
|
function monitor() {
|
|
if (main._timer) return;
|
|
var ts = (new Date()).getTime();
|
|
if (ts - main._lastTimer > 30000) {
|
|
// It seems, that PC was in a sleep => Reload page to request authentication anew
|
|
location.reload();
|
|
} else {
|
|
main._lastTimer = ts;
|
|
}
|
|
main._timer = setTimeout(function () {
|
|
main._timer = null;
|
|
monitor();
|
|
}, 10000);
|
|
}
|
|
|
|
// ---------------------------- Subscribes ---------------------------------------------
|
|
main.resubscribeStates = function () {
|
|
for (var pattern in main.subscribesStates) {
|
|
if (main.subscribesStates.hasOwnProperty(pattern) && main.subscribesStates[pattern]) {
|
|
console.debug('Re-Subscribe: ' + pattern);
|
|
main.socket.emit('subscribe', pattern);
|
|
}
|
|
}
|
|
};
|
|
|
|
main.resubscribeObjects = function () {
|
|
for (var pattern in main.subscribesObjects) {
|
|
if (main.subscribesObjects.hasOwnProperty(pattern) && main.subscribesObjects[pattern]) {
|
|
main.socket.emit('subscribeObjects', pattern);
|
|
}
|
|
}
|
|
};
|
|
|
|
main.resubscribeLogs = function () {
|
|
if (main.subscribesLogs) {
|
|
console.debug('Subscribe LOG');
|
|
main.socket.emit('requireLog', true);
|
|
}
|
|
};
|
|
|
|
main.subscribeStates = function (patterns) {
|
|
if (!patterns) return;
|
|
if (typeof patterns === 'object') {
|
|
for (var s = 0; s < patterns.length; s++) {
|
|
main.subscribesStates[patterns[s]] = main.subscribesStates[patterns[s]] || 0;
|
|
main.subscribesStates[patterns[s]]++;
|
|
if (main.subscribesStates[patterns[s]] === 1) {
|
|
console.debug('Subscribe: ' + patterns[s]);
|
|
main.socket.emit('subscribe', patterns[s]);
|
|
}
|
|
}
|
|
} else {
|
|
main.subscribesStates[patterns] = main.subscribesStates[patterns] || 0;
|
|
main.subscribesStates[patterns]++;
|
|
if (main.subscribesStates[patterns] === 1) {
|
|
console.debug('Subscribe: ' + patterns);
|
|
main.socket.emit('subscribe', patterns);
|
|
}
|
|
}
|
|
};
|
|
|
|
main.unsubscribeStates = function (patterns) {
|
|
if (!patterns) return;
|
|
if (typeof patterns === 'object') {
|
|
for (var s = 0; s < patterns.length; s++) {
|
|
if (main.subscribesStates[patterns[s]]) {
|
|
main.subscribesStates[patterns[s]]--;
|
|
}
|
|
if (main.subscribesStates[patterns[s]] === 0) {
|
|
console.debug('Unsibscribe: ' + patterns[s]);
|
|
main.socket.emit('unsubscribe', patterns[s]);
|
|
delete main.subscribesStates[patterns[s]];
|
|
}
|
|
}
|
|
} else {
|
|
if (main.subscribesStates[patterns]) {
|
|
main.subscribesStates[patterns]--;
|
|
}
|
|
if (main.subscribesStates[patterns] === 0) {
|
|
console.debug('Unsibscribe: ' + patterns);
|
|
main.socket.emit('unsubscribe', patterns);
|
|
delete main.subscribesStates[patterns];
|
|
}
|
|
}
|
|
};
|
|
|
|
main.subscribeObjects = function (patterns) {
|
|
if (!patterns) return;
|
|
if (typeof patterns === 'object') {
|
|
for (var s = 0; s < patterns.length; s++) {
|
|
main.subscribesObjects[patterns[s]] = main.subscribesObjects[patterns[s]] || 0;
|
|
main.subscribesObjects[patterns[s]]++;
|
|
if (main.subscribesObjects[patterns[s]] === 1) {
|
|
main.socket.emit('subscribeObjects', patterns[s]);
|
|
}
|
|
}
|
|
} else {
|
|
main.subscribesObjects[patterns] = main.subscribesObjects[patterns] || 0;
|
|
main.subscribesObjects[patterns]++;
|
|
if (main.subscribesObjects[patterns] === 1) {
|
|
main.socket.emit('subscribeObjects', patterns);
|
|
}
|
|
}
|
|
};
|
|
|
|
main.unsubscribeObjects = function (patterns) {
|
|
if (!patterns) return;
|
|
if (typeof patterns === 'object') {
|
|
for (var s = 0; s < patterns.length; s++) {
|
|
if (main.subscribesObjects[patterns[s]]) {
|
|
main.subscribesObjects[patterns[s]]--;
|
|
}
|
|
if (main.subscribesObjects[patterns[s]] === 0) {
|
|
main.socket.emit('unsubscribeObjects', patterns[s]);
|
|
delete main.subscribesObjects[patterns[s]];
|
|
}
|
|
}
|
|
} else {
|
|
if (main.subscribesObjects[patterns]) {
|
|
main.subscribesObjects[patterns]--;
|
|
}
|
|
if (main.subscribesObjects[patterns] === 0) {
|
|
main.socket.emit('unsubscribeObjects', patterns);
|
|
delete main.subscribesObjects[patterns];
|
|
}
|
|
}
|
|
};
|
|
|
|
main.subscribeLogs = function (isSubscribe) {
|
|
if (isSubscribe) {
|
|
main.subscribesLogs++;
|
|
if (main.subscribesLogs === 1) {
|
|
console.debug('Subscribe Logs');
|
|
main.socket.emit('requireLog', true);
|
|
}
|
|
} else {
|
|
main.subscribesLogs--;
|
|
if (main.subscribesLogs <= 0) {
|
|
main.subscribesLogs = 0;
|
|
console.debug('Unsubscribe Logs');
|
|
main.socket.emit('requireLog', false);
|
|
}
|
|
}
|
|
};
|
|
|
|
// ---------------------------- Navigation ---------------------------------------------
|
|
main.navigateCheckDialog = function (callback) {
|
|
if (main.currentDialog && main.dialogs[main.currentDialog] && typeof main.dialogs[main.currentDialog].allStored === 'function') {
|
|
if (main.dialogs[main.currentDialog].allStored() === false) {
|
|
return main.confirmMessage(_('Some data are not stored. Discard?'), _('Please confirm'), null, function (result) {
|
|
callback(!result);
|
|
});
|
|
}
|
|
} else {
|
|
if (configNotSaved) {
|
|
return main.confirmMessage(_('Some data are not stored. Discard?'), _('Please confirm'), null, function (result) {
|
|
callback(!result);
|
|
});
|
|
}
|
|
}
|
|
callback(false);
|
|
};
|
|
|
|
main.navigateGetParams = function () {
|
|
var parts = decodeURI(window.location.hash).split('/');
|
|
return parts[2] ? decodeURIComponent(parts[2]) : null;
|
|
};
|
|
|
|
main.navigate = function (options) {
|
|
if (!options) {
|
|
options = {};
|
|
}
|
|
if (typeof options === 'string') {
|
|
options = {
|
|
tab: options,
|
|
dialog: '',
|
|
params: ''
|
|
};
|
|
}
|
|
|
|
// get actual tab
|
|
if (!options.tab) {
|
|
var parts = decodeURI(window.location.hash).split('/');
|
|
options.tab = parts[0].replace(/^#/, '').replace(/^tab-/, '');
|
|
}
|
|
|
|
window.location.hash = '#tab-' + encodeURIComponent(options.tab) + (options.dialog ? '/' + options.dialog + (options.params ? '/' + encodeURIComponent(options.params) : '') : '');
|
|
};
|
|
|
|
// Router
|
|
main.navigateDo = function () {
|
|
// ignore if hash not changed
|
|
if (window.location.hash === main.currentHash) {
|
|
return;
|
|
}
|
|
// if config dialog opened and has some unsaved data
|
|
main.navigateCheckDialog(function (err) {
|
|
if (!err) {
|
|
configNotSaved = null;
|
|
main.currentHash = window.location.hash;
|
|
// hash has following structure => #tabName/dialogName/ids
|
|
var parts = main.currentHash.split('/');
|
|
var tab = parts[0].replace(/^#/, '').replace(/^tab-/, '');
|
|
var dialog = parts[1];
|
|
var params = decodeURIComponent(parts[2]);
|
|
|
|
// set default page
|
|
if (!tab || tab === '!') {
|
|
if (!main.systemConfig.common.tabs || main.systemConfig.common.tabs.indexOf('tab-intro') !== -1) {
|
|
tab = 'intro';
|
|
} else if (main.systemConfig.common.tabs.indexOf('tab-adapters') !== -1) {
|
|
tab = 'adapters';
|
|
} else {
|
|
tab = main.systemConfig.common.tabs[0].replace(/^#/, '').replace(/^tab-/, '');
|
|
}
|
|
}
|
|
// do tab is not found
|
|
|
|
var $adminBody = $('.admin-sidemenu-body');
|
|
var $actualTab = $adminBody.find('.admin-sidemenu-body-content');
|
|
var $panel = $('#tab-' + tab);
|
|
|
|
$adminBody.find('.admin-preloader').remove();
|
|
|
|
if (!$panel.length) {
|
|
tab = 'intro';
|
|
}
|
|
|
|
// if tab was changed
|
|
if (main.currentTab !== tab || !$actualTab.length) {
|
|
var link;
|
|
// destroy actual tab
|
|
if (main.currentTab && tabs[main.currentTab] && typeof tabs[main.currentTab].destroy === 'function') {
|
|
tabs[main.currentTab].destroy();
|
|
} else if (main.currentTab) {
|
|
var $oldPanel = $('#tab-' + main.currentTab);
|
|
// destroy current iframe
|
|
if ($oldPanel.length && (link = $oldPanel.data('src'))) {
|
|
var $iframe_ = $oldPanel.find('>iframe');
|
|
if ($iframe_.attr('src')) {
|
|
console.log('clear');
|
|
$iframe_.attr('src', '');
|
|
}
|
|
}
|
|
}
|
|
main.currentTab = tab;
|
|
|
|
$actualTab.hide().appendTo('body');
|
|
if (!dialog) {
|
|
$panel.addClass('admin-sidemenu-body-content').show().appendTo($adminBody);
|
|
$actualTab = $panel;
|
|
}
|
|
|
|
// init new tab
|
|
if (tabs[tab] && typeof tabs[tab].init === 'function') {
|
|
tabs[tab].init();
|
|
}
|
|
|
|
// if iframe like node-red
|
|
if ($panel.length && (link = $panel.data('src'))) {
|
|
if (link.indexOf('%') === -1) {
|
|
var $iframe = $panel.find('>iframe');
|
|
if ($iframe.length && !$iframe.attr('src')) {
|
|
$iframe.attr('src', link);
|
|
}
|
|
} else {
|
|
$adminSideMenu.data('problem-link', 'tab-' + tab);
|
|
}
|
|
}
|
|
}
|
|
|
|
// select menu element
|
|
var $tab = $adminSideMenu.find('.admin-sidemenu-items[data-tab="tab-' + tab + '"]');
|
|
$adminSideMenu.find('.admin-sidemenu-items').not($tab).removeClass('admin-sidemenu-active');
|
|
$tab.addClass('admin-sidemenu-active');
|
|
|
|
if (tabsInfo['tab-' + tab] && tabsInfo['tab-' + tab].host) {
|
|
$('#host-adapters-btn').css('opacity', 1);
|
|
} else {
|
|
$('#host-adapters-btn').css('opacity', 0.3);
|
|
}
|
|
document.title = tab + ' - yunkong2';
|
|
// if some dialog opened or must be shown
|
|
if (main.currentDialog !== dialog) {
|
|
// destroy it
|
|
if (main.dialogs[main.currentDialog] && typeof main.dialogs[main.currentDialog].destroy === 'function') {
|
|
main.dialogs[main.currentDialog].destroy();
|
|
}
|
|
main.currentDialog = dialog;
|
|
if (dialog && main.dialogs[dialog]) {
|
|
if (typeof main.dialogs[dialog].init === 'function') {
|
|
main.dialogs[dialog].init(params ? params.split(',') : undefined);
|
|
}
|
|
tabs[main.currentTab] && tabs[main.currentTab].saveScroll && tabs[main.currentTab].saveScroll();
|
|
$actualTab.hide().appendTo('body');
|
|
$('#dialog-' + dialog).addClass('admin-sidemenu-body-content').show().appendTo($adminBody);
|
|
} else if ($actualTab.attr('id') !== $panel.attr('id')) {
|
|
$actualTab.hide().appendTo('body');
|
|
$panel.addClass('admin-sidemenu-body-content').show().appendTo($adminBody);
|
|
tabs[main.currentTab] && tabs[main.currentTab].restoreScroll && tabs[main.currentTab].restoreScroll();
|
|
}
|
|
}
|
|
} else {
|
|
// restore hash link
|
|
window.location.hash = main.currentHash || '';
|
|
}
|
|
});
|
|
};
|
|
|
|
function getIconHtml(obj, classes) {
|
|
var icon;
|
|
var alt;
|
|
var isCommon = obj && obj.common;
|
|
|
|
if (isCommon.icon) {
|
|
if (!isCommon.icon.match(/^data:image\//)) {
|
|
if (isCommon.icon.indexOf('.') !== -1) {
|
|
var instance;
|
|
if (obj.type === 'instance') {
|
|
icon = '/adapter/' + obj.common.name + '/' + obj.common.icon;
|
|
} else if (obj._id.match(/^system\.adapter\./)) {
|
|
instance = obj._id.split('.', 3);
|
|
if (isCommon.icon[0] === '/') {
|
|
instance[2] += isCommon.icon;
|
|
} else {
|
|
instance[2] += '/' + isCommon.icon;
|
|
}
|
|
icon = '/adapter/' + instance[2];
|
|
} else {
|
|
instance = obj._id.split('.', 2);
|
|
if (isCommon.icon[0] === '/') {
|
|
instance[0] += isCommon.icon;
|
|
} else {
|
|
instance[0] += '/' + isCommon.icon;
|
|
}
|
|
icon = '/adapter/' + instance[0];
|
|
}
|
|
} else {
|
|
return '<i class="material-icons ' + (classes || 'treetable-icon') + '">' + isCommon.icon + '</i>';
|
|
}
|
|
|
|
} else {
|
|
icon = isCommon.icon;
|
|
}
|
|
alt = obj.type;
|
|
}
|
|
return {icon: icon, alt: alt}
|
|
}
|
|
|
|
main.getIconFromObj = function (obj, imgPath, classes) {
|
|
var icon = '';
|
|
var alt = '';
|
|
if (obj && obj.common) {
|
|
if (obj.common.icon) {
|
|
var result = getIconHtml(obj);
|
|
icon = result.icon;
|
|
alt = result.alt;
|
|
} else {
|
|
imgPath = imgPath || 'lib/css/fancytree/';
|
|
if (obj.type === 'device') {
|
|
icon = imgPath + 'device.png';
|
|
alt = 'device';
|
|
} else if (obj.type === 'channel') {
|
|
icon = imgPath + 'channel.png';
|
|
alt = 'channel';
|
|
} else if (obj.type === 'state') {
|
|
icon = imgPath + 'state.png';
|
|
alt = 'state';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (icon) return '<img class="' + (classes || 'treetable-icon') + '" src="' + icon + '" alt="' + (alt || '') + '" />';
|
|
return '';
|
|
};
|
|
|
|
// static, just used from many places
|
|
main.getIcon = function(id, imgPath, objects, classes) {
|
|
return main.getIconFromObj((objects || main.objects)[id], imgPath, classes);
|
|
};
|
|
|
|
main.getHostIcon = function (obj, classes) {
|
|
var icon = '';
|
|
var alt = '';
|
|
|
|
if (obj && obj.common && obj.common.icon) {
|
|
var result = getIconHtml(obj);
|
|
icon = result.icon;
|
|
alt = result.alt;
|
|
}
|
|
icon = icon || 'img/no-image.png';
|
|
alt = alt || '';
|
|
|
|
return '<img class="' + (classes || 'treetable-icon') + '" src="' + icon + '" alt="' + alt + '" />';
|
|
};
|
|
|
|
main.formatBytes = function (bytes) {
|
|
if (Math.abs(bytes) < 1024) {
|
|
return bytes + ' B';
|
|
}
|
|
var units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
|
|
var u = -1;
|
|
do {
|
|
bytes /= 1024;
|
|
++u;
|
|
} while (Math.abs(bytes) >= 1024 && u < units.length - 1);
|
|
return bytes.toFixed(1) + ' ' + units[u];
|
|
};
|
|
|
|
// https://stackoverflow.com/questions/35969656/how-can-i-generate-the-opposite-color-according-to-current-color
|
|
main.invertColor = function (hex) {
|
|
if (hex.indexOf('#') === 0) {
|
|
hex = hex.slice(1);
|
|
}
|
|
// convert 3-digit hex to 6-digits.
|
|
if (hex.length === 3) {
|
|
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
|
}
|
|
if (hex.length !== 6) {
|
|
return false;
|
|
}
|
|
var r = parseInt(hex.slice(0, 2), 16),
|
|
g = parseInt(hex.slice(2, 4), 16),
|
|
b = parseInt(hex.slice(4, 6), 16);
|
|
// http://stackoverflow.com/a/3943023/112731
|
|
return (r * 0.299 + g * 0.587 + b * 0.114) <= 186;
|
|
};
|
|
|
|
var tabsInfo = {
|
|
'tab-intro': {order: 1, icon: 'apps'},
|
|
'tab-adapters': {order: 2, icon: 'store', host: true},
|
|
'tab-instances': {order: 3, icon: 'subtitles', host: true},
|
|
'tab-objects': {order: 4, icon: 'view_list'},
|
|
'tab-enums': {order: 5, icon: 'art_track'},
|
|
'tab-logs': {order: 6, icon: 'view_headline', host: true},
|
|
'tab-scenes': {order: 7, icon: 'subscriptions'},
|
|
'tab-events': {order: 8, icon: 'flash_on'},
|
|
'tab-users': {order: 10, icon: 'person_outline'},
|
|
'tab-javascript': {order: 11, icon: 'code'},
|
|
'tab-text2command-0': {order: 12, icon: 'ac_unit'},
|
|
'tab-text2command-1': {order: 12, icon: 'ac_unit'},
|
|
'tab-text2command-2': {order: 12, icon: 'ac_unit'},
|
|
'tab-node-red-0': {order: 20, icon: 'device_hub'},
|
|
'tab-node-red-1': {order: 21, icon: 'device_hub'},
|
|
'tab-node-red-2': {order: 22, icon: 'device_hub'},
|
|
'tab-hosts': {order: 100, icon: 'storage'},
|
|
'tab-fullcalendar-0': {order: 30, icon: 'perm_contact_calendar'},
|
|
'tab-fullcalendar-1': {order: 31, icon: 'perm_contact_calendar'},
|
|
'tab-fullcalendar-2': {order: 32, icon: 'perm_contact_calendar'}
|
|
};
|
|
|
|
function initSideNav() {
|
|
var lines = '';
|
|
|
|
var elements = [];
|
|
$('.admin-tab').each(function () {
|
|
var id = $(this).attr('id');
|
|
if (!main.systemConfig.common.tabs || main.systemConfig.common.tabs.indexOf(id) !== -1) {
|
|
elements.push({
|
|
line: '<li class="admin-sidemenu-items" data-tab="' + id + '"><a href="#' + id + '">' +
|
|
(tabsInfo[id] && tabsInfo[id].icon ? '<i class="material-icons left">' + tabsInfo[id].icon + '</i>' : '<i class="material-icons left">live_help</i>') +
|
|
_($(this).data('name')) + '</a></li>',
|
|
id: id
|
|
});
|
|
}
|
|
});
|
|
$('.tab-custom').each(function () {
|
|
var id = $(this).attr('id');
|
|
if (!main.systemConfig.common.tabs || main.systemConfig.common.tabs.indexOf(id) !== -1) {
|
|
var icon;
|
|
if (tabsInfo[id] && tabsInfo[id].icon) {
|
|
icon = tabsInfo[id].icon;
|
|
} else {
|
|
var _id = 'system.adapter.' + id.substring(4);
|
|
if (main.objects[_id] && main.objects[_id].adminTab && main.objects[_id]['fa-icon']) {
|
|
icon = main.objects[_id]['fa-icon'];
|
|
}
|
|
}
|
|
|
|
elements.push({
|
|
line: '<li class="admin-sidemenu-items" data-tab="' + id + '"><a href="#' + id + '">' +
|
|
(icon ? '<i class="material-icons left">' + icon + '</i>' : '<i class="material-icons left">live_help</i>') +
|
|
$(this).data('name') + '</a></li>',
|
|
id: id
|
|
});
|
|
}
|
|
});
|
|
|
|
elements.sort(function (a, b) {
|
|
if (!tabsInfo[a.id] && !tabsInfo[b.id]) return 0;
|
|
if (!tabsInfo[a.id]) return 1;
|
|
if (!tabsInfo[b.id]) return -1;
|
|
if (tabsInfo[a.id].order < tabsInfo[b.id].order) return -1;
|
|
if (tabsInfo[a.id].order > tabsInfo[b.id].order) return 1;
|
|
return 0;
|
|
});
|
|
|
|
for (var e = 0; e < elements.length; e++) {
|
|
lines += elements[e].line;
|
|
}
|
|
$adminSideMenu.find('.admin-sidemenu-menu').html(lines);
|
|
|
|
$('.admin-sidemenu-close').off('click').on('click', function () {
|
|
$adminSideMain.toggleClass('admin-sidemenu-closed');
|
|
$adminSideMenu.toggleClass('admin-sidemenu-closed');
|
|
$('.admin-sidemenu-close i').toggleClass('hide');
|
|
|
|
setTimeout(function () {
|
|
//resizeGrids();
|
|
$(window).trigger('resize');
|
|
}, 400);
|
|
});
|
|
|
|
$('.admin-sidemenu-items').off('click').on('click', function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
window.location.hash = '#' + $(this).data('tab');
|
|
});
|
|
$('.admin-sidemenu-items a').off('click').on('click', function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
window.location.hash = '#' + $(this).parent().data('tab');
|
|
});
|
|
|
|
// Show if update available
|
|
tabs.hosts.updateCounter();
|
|
tabs.adapters.updateCounter();
|
|
}
|
|
|
|
// ---------------------------- Socket.io methods ---------------------------------------------
|
|
main.socket.on('log', function (message) {
|
|
tabs.logs.add(message);
|
|
});
|
|
main.socket.on('error', function (error) {
|
|
console.log(error);
|
|
});
|
|
main.socket.on('permissionError', function (err) {
|
|
main.showMessage(_('Has no permission to %s %s %s', err.operation, err.type, (err.id || '')));
|
|
});
|
|
main.socket.on('stateChange', function (id, obj) {
|
|
setTimeout(stateChange, 0, id, obj);
|
|
});
|
|
main.socket.on('objectChange', function (id, obj) {
|
|
setTimeout(objectChange, 0, id, obj);
|
|
});
|
|
main.socket.on('cmdStdout', function (_id, text) {
|
|
if (activeCmdId === _id) {
|
|
var m = text.match(/^upload \[(\d+)]/);
|
|
if (m) {
|
|
if ($dialogCommand.data('max') === null) {
|
|
$dialogCommand.data('max', parseInt(m[1], 10));
|
|
$dialogCommandProgress.removeClass('indeterminate').addClass('determinate');
|
|
}
|
|
var max = $dialogCommand.data('max');
|
|
var value = parseInt(m[1], 10);
|
|
$dialogCommandProgress.css('width', (100 - Math.round((value / max) * 100)) + '%');
|
|
} else {
|
|
m = text.match(/^got [-_:\/\\.\w\d]+\/admin$/);
|
|
if (m) {
|
|
// upload of admin
|
|
$dialogCommand.find('.progress-text').html(_('Upload admin started'));
|
|
$dialogCommand.data('max', null);
|
|
} else {
|
|
// got ..../www
|
|
m = text.match(/^got [-_:\/\\.\w\d]+\/www$/);
|
|
if (m) {
|
|
// upload of www
|
|
$dialogCommand.find('.progress-text').html(_('Upload www started'));
|
|
$dialogCommand.data('max', null);
|
|
} else {
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
stdout += '\n' + text;
|
|
$stdout.val(stdout);
|
|
$stdout.scrollTop($stdout[0].scrollHeight - $stdout.height());
|
|
}
|
|
});
|
|
main.socket.on('cmdStderr', function (_id, text) {
|
|
if (activeCmdId === _id) {
|
|
if (!$dialogCommand.data('error')) {
|
|
$dialogCommand.data('error', text);
|
|
}
|
|
stdout += '\nERROR: ' + text;
|
|
$stdout.val(stdout);
|
|
$stdout.scrollTop($stdout[0].scrollHeight - $stdout.height());
|
|
}
|
|
});
|
|
main.socket.on('cmdExit', function (_id, exitCode) {
|
|
if (activeCmdId === _id) {
|
|
|
|
exitCode = parseInt(exitCode, 10);
|
|
stdout += '\n' + (exitCode !== 0 ? 'ERROR: ' : '') + 'process exited with code ' + exitCode;
|
|
$stdout.val(stdout);
|
|
$stdout.scrollTop($stdout[0].scrollHeight - $stdout.height());
|
|
|
|
$dialogCommand.find('.progress-dont-close').addClass('disabled');
|
|
$dialogCommandProgress.removeClass('indeterminate').css({'width': '100%'});
|
|
$dialogCommand.find('.btn').html(_('Close'));
|
|
$dialogCommand.data('finished', true);
|
|
$dialogCommand.data('max', true);
|
|
var $backButton = $adminSideMain.find('.button-command');
|
|
$backButton.removeClass('in-progress');
|
|
|
|
if (!exitCode) {
|
|
$dialogCommand.find('.progress-text').html(_('Success!'));
|
|
$backButton.hide();
|
|
if ($dialogCommand.find('.progress-dont-close input').prop('checked')) {
|
|
setTimeout(function () {
|
|
$dialogCommand.modal('close');
|
|
}, 1500);
|
|
}
|
|
} else {
|
|
var error = $dialogCommand.data('error');
|
|
if (error) {
|
|
var m = error.match(/error: (.*)$/);
|
|
if (m) {
|
|
error = m[1];
|
|
}
|
|
|
|
$dialogCommand.find('.progress-text').html(_('Done with error: %s', _(error))).addClass('error');
|
|
} else {
|
|
$dialogCommand.find('.progress-text').html(_('Done with error')).addClass('error');
|
|
}
|
|
$backButton.addClass('error');
|
|
$backButton.show();
|
|
}
|
|
if (cmdCallback) {
|
|
cmdCallback(exitCode);
|
|
cmdCallback = null;
|
|
}
|
|
}
|
|
});
|
|
main.socket.on('eventsThreshold', function (isActive) {
|
|
if (isActive) {
|
|
$('#events_threshold').show();
|
|
} else {
|
|
$('#events_threshold').hide();
|
|
}
|
|
});
|
|
main.socket.on('connect', function () {
|
|
$('#connecting').hide();
|
|
if (firstConnect) {
|
|
firstConnect = false;
|
|
|
|
main.getUser();
|
|
|
|
main.socket.emit('getUserPermissions', function (err, acl) {
|
|
main.acl = acl;
|
|
// Read system configuration
|
|
main.socket.emit('getObject', 'system.config', function (errConfig, data) {
|
|
main.systemConfig = data;
|
|
|
|
// set logo and set branding
|
|
if (data && data.native && data.native.vendor) {
|
|
var vendor = data.native.vendor;
|
|
if (vendor.icon) {
|
|
$('.admin-sidemenu-header .button-icon img').attr('src', data.native.vendor.icon);
|
|
}
|
|
if (vendor.name) {
|
|
$('.admin-sidemenu-header .button-version').html(data.native.vendor.name).addClass('vendor');
|
|
}
|
|
if (vendor.admin && vendor.admin.noCustomInstall) {
|
|
$('#btn_filter_custom_url').hide();
|
|
}
|
|
if (vendor.admin && vendor.admin.css) {
|
|
if (vendor.admin.css.sideNavUser) {
|
|
$('.side-nav .user-view').css(vendor.admin.css.sideNavUser);
|
|
}
|
|
if (vendor.admin.css.sideNavMenu) {
|
|
$('.side-nav').css(vendor.admin.css.sideNavMenu);
|
|
}
|
|
if (vendor.admin.css.header) {
|
|
$adminSideMain.find('.admin-sidemenu-header nav').css(vendor.admin.css.header);
|
|
}
|
|
// apply rules
|
|
if (vendor.admin.css.rules) {
|
|
for (var r = 0; r < vendor.admin.css.rules.length; r++) {
|
|
$(vendor.admin.css.rules[r].selector).css(vendor.admin.css.rules[r].css);
|
|
}
|
|
}
|
|
if (vendor.admin.styles) {
|
|
$('head').append('<style type="text/css">' + vendor.admin.styles + '</style>');
|
|
}
|
|
}
|
|
}
|
|
|
|
// rename log => logs (back compatibility)
|
|
if (main.systemConfig && main.systemConfig.common && main.systemConfig.common.tabs) {
|
|
var pos = main.systemConfig.common.tabs.indexOf('tab-log');
|
|
if (pos !== -1) {
|
|
main.systemConfig.common.tabs[pos] = 'tab-logs';
|
|
}
|
|
}
|
|
|
|
main.socket.emit('getObject', 'system.repositories', function (errRepo, repo) {
|
|
main.dialogs.system.systemRepos = repo;
|
|
main.socket.emit('getObject', 'system.certificates', function (errCerts, certs) {
|
|
setTimeout(function () {
|
|
main.dialogs.system.systemCerts = certs;
|
|
if (errConfig === 'permissionError') {
|
|
main.systemConfig = {common: {language: systemLang}, error: 'permissionError'};
|
|
} else {
|
|
if (!errConfig && main.systemConfig && main.systemConfig.common) {
|
|
systemLang = main.systemConfig.common.language || systemLang;
|
|
main.systemConfig.common.city = main.systemConfig.common.city || '';
|
|
main.systemConfig.common.country = main.systemConfig.common.country || '';
|
|
main.systemConfig.common.longitude = main.systemConfig.common.longitude || '';
|
|
main.systemConfig.common.latitude = main.systemConfig.common.latitude || '';
|
|
|
|
if (!main.systemConfig.common.licenseConfirmed) {
|
|
// Show license agreement
|
|
var language = (main.systemConfig.common.language || window.navigator.userLanguage || window.navigator.language || '').substring(0, 2);
|
|
if (language !== 'en' && language !== 'de' && language !== 'ru') language = 'en';
|
|
|
|
systemLang = language;
|
|
|
|
$dialogLicense.find('.license_text').html(license[language] || license.en);
|
|
|
|
$dialogLicense.find('.license_checkbox').prop('checked', false);
|
|
|
|
// on language change
|
|
$dialogLicense.find('.license_language')
|
|
.data('licenseConfirmed', false)
|
|
.val(language)
|
|
.on('change', function () {
|
|
language = $(this).val();
|
|
$dialogLicense.find('.license_language_label').html(translateWord('Select language', language));
|
|
$dialogLicense.find('.license_text').html(license[language] || license.en);
|
|
$dialogLicense.find('.license_checkbox').html(translateWord('license_checkbox', language));
|
|
$dialogLicense.find('.license_agree .translate').html(translateWord('agree', language));
|
|
$dialogLicense.find('.license_non_agree .translate').html(translateWord('not agree', language));
|
|
$dialogLicense.find('.license_terms').html(translateWord('License terms', language));
|
|
$dialogLicense.find('.license_agreement_label').html(translateWord('license agreement', language));
|
|
}).select();
|
|
|
|
$dialogLicense.find('.license_diag').on('change', function () {
|
|
if ($(this).prop('checked')) {
|
|
$dialogLicense.find('.license_agree').removeClass('disabled');
|
|
} else {
|
|
$dialogLicense.find('.license_agree').addClass('disabled');
|
|
}
|
|
});
|
|
|
|
// workaround for materialize checkbox problem
|
|
$dialogLicense.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');
|
|
}
|
|
});
|
|
|
|
$dialogLicense.modal({
|
|
dismissible: false,
|
|
complete: function () {
|
|
$dialogLicense.find('.license_text').html('');
|
|
location.reload();
|
|
}
|
|
}).modal('open');
|
|
|
|
$dialogLicense.find('.license_agree').addClass('disabled').off('click').on('click', function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
main.socket.emit('getObject', 'system.config', function (err, obj) {
|
|
if (err || !obj) {
|
|
main.showError(_('Cannot confirm: ' + err));
|
|
return;
|
|
}
|
|
obj.common = obj.common || {};
|
|
obj.common.licenseConfirmed = true;
|
|
obj.common.language = language;
|
|
main.socket.emit('setObject', 'system.config', obj, function (err) {
|
|
if (err) {
|
|
main.showError(err);
|
|
}
|
|
$dialogLicense.modal('close');
|
|
$dialogLicense.find('.license_agree').off('click');
|
|
$dialogLicense.find('.license_non_agree').off('click');
|
|
});
|
|
});
|
|
});
|
|
$dialogLicense.find('.license_non_agree').off('click').on('click', function (e) {
|
|
location.reload();
|
|
});
|
|
}
|
|
} else {
|
|
main.systemConfig = {
|
|
type: 'config',
|
|
common: {
|
|
name: 'system.config',
|
|
city: '', // City for weather
|
|
country: '', // Country for weather
|
|
longitude: '', // longitude for javascript
|
|
latitude: '', // longitude for javascript
|
|
language: '', // Default language for adapters. Adapters can use different values.
|
|
tempUnit: '°C', // Default temperature units.
|
|
currency: '', // Default currency sign.
|
|
dateFormat: 'DD.MM.YYYY', // Default date format.
|
|
isFloatComma: true, // Default float divider ('.' - false, ',' - true)
|
|
licenseConfirmed: false, // If license agreement confirmed,
|
|
defaultHistory: '', // Default history instance
|
|
tabs: [ // Show by default only these tabs
|
|
'tab-intro',
|
|
'tab-adapters',
|
|
'tab-instances',
|
|
'tab-objects',
|
|
'tab-logs',
|
|
'tab-scenes',
|
|
'tab-javascript',
|
|
'tab-text2command-0'
|
|
]
|
|
}
|
|
};
|
|
main.systemConfig.common.language = window.navigator.userLanguage || window.navigator.language;
|
|
|
|
if (main.systemConfig.common.language !== 'en' && main.systemConfig.common.language !== 'de' && main.systemConfig.common.language !== 'ru') {
|
|
main.systemConfig.common.language = 'en';
|
|
}
|
|
}
|
|
}
|
|
|
|
translateCron();
|
|
translateAll();
|
|
|
|
// Here we go!
|
|
initAllDialogs();
|
|
// call prepare
|
|
for (var t in tabs) {
|
|
if (tabs.hasOwnProperty(t) && tabs[t] && typeof tabs[t].prepare === 'function') {
|
|
tabs[t].prepare();
|
|
}
|
|
}
|
|
// TABS
|
|
// resizeGrids();
|
|
|
|
getStates(getObjects);
|
|
}, 0);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
} else {
|
|
main.resubscribeStates();
|
|
main.resubscribeObjects();
|
|
main.resubscribeLogs();
|
|
}
|
|
if (main.waitForRestart) {
|
|
location.reload();
|
|
}
|
|
});
|
|
main.socket.on('disconnect', function () {
|
|
$('#connecting').show();
|
|
});
|
|
main.socket.on('reconnect', function () {
|
|
$('#connecting').hide();
|
|
if (main.waitForRestart) {
|
|
location.reload();
|
|
}
|
|
});
|
|
main.socket.on('repoUpdated', function () {
|
|
setTimeout(function () {
|
|
tabs.adapters.init(true);
|
|
}, 0);
|
|
});
|
|
main.socket.on('reauthenticate', function () {
|
|
location.reload();
|
|
});
|
|
|
|
/*function resizeGrids() {
|
|
var x = $(window).width();
|
|
var y = $(window).height();
|
|
if (x < 720) {
|
|
x = 720;
|
|
}
|
|
if (y < 480) {
|
|
y = 480;
|
|
}
|
|
for (var tab in tabs.events) {
|
|
if (tabs.events.hasOwnProperty(tab) && tabs[tab] && tabs[tab].resize) {
|
|
tabs[tab].resize(x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
$(window).resize(resizeGrids);
|
|
*/
|
|
});
|
|
})(jQuery);
|