/* 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( '' + _('Ok') + '' + '' + _('Cancel') + ''); $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 += '' + buttons[b] + ''; } $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 ? '' + icon + '' : ''), 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('account_circle'); } $('#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 one object or all 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 "%s" 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 = '' + // style="overflow: visible; z-index: 999; ">' '
' + '' + '
' + '
'; $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 += '
  • ' + buttonName + '
  • \n'; // noinspection JSJQueryEfficiency if (!$('#' + name).length) { var 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(''); }); } 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('
  • ' + main.getHostIcon(main.objects[main.tabs.hosts.list[i].id], 'imgHost left') + main.tabs.hosts.list[i].name + '
  • '); 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 '' + isCommon.icon + ''; } } 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 '' + (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 '' + 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: '
  • ' + (tabsInfo[id] && tabsInfo[id].icon ? '' + tabsInfo[id].icon + '' : 'live_help') + _($(this).data('name')) + '
  • ', 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: '
  • ' + (icon ? '' + icon + '' : 'live_help') + $(this).data('name') + '
  • ', 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(''); } } } // 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 = 'cn'; 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 = 'cn'; } } } 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);