';
}
if (!obj) {
$tdList.eq(0).css({'font-weight': 'bold'});
$tdList.eq(0).find('img').remove();
$tdList.eq(0).find('span.fancytree-title').attr('style', 'padding-left: 0px !important');
// Calculate total count of adapter and count of installed adapter
for (var c = 0; c < that.tree.length; c++) {
if (that.tree[c].key === node.key) {
$tdList.eq(1).html(that.tree[c].desc || '').css({'overflow': 'hidden', 'white-space': 'nowrap', position: 'relative'});
var installed = 0;
for (var k = 0; k < that.tree[c].children.length; k++) {
if (that.data[that.tree[c].children[k].key].installed) installed++;
}
that.tree[c].installed = installed;
node.data.installed = installed;
var title;
//if (!that.onlyInstalled && !that.onlyUpdatable) {
title = '[' + installed + ' / ' + that.tree[c].children.length + ']';
$tdList.eq(1).html(ellipsis('' + installed + ' ' + _('of') + ' ' + that.tree[c].children.length + ' ' + _('Adapters from this Group installed')));
break;
}
}
return;
}
$tdList.eq(0).css({'overflow': 'hidden', 'white-space': 'nowrap'});
function setHtml(no, html) {
return $tdList.eq(no).html(ellipsis(html));
}
var idx = obj.desc.indexOf('
= 0 ? obj.desc.substr(0, idx) : obj.desc;
$tdList.eq(1).html(ellipsis(obj.desc))
.attr('title', desc)
.css({'white-space': 'nowrap', position: 'relative', 'font-weight': obj.bold ? 'bold' : null}).find('>div>div')
.css('height: 22px !important')
;
setHtml(2, obj.keywords).attr('title', obj.keywords);
$tdList.eq(3).html(obj.installed);
$tdList.eq(4).html(obj.version); //.css({ position: 'relative'});
// setHtml(5, obj.platform);// actually there is only one platform
setHtml(5, obj.license);
setHtml(6, obj.install);
that.initButtons(node.key);
// If we render this element, that means it is expanded
if (that.isCollapsed[obj.group]) {
that.isCollapsed[obj.group] = false;
that.main.saveConfig('adaptersIsCollapsed', JSON.stringify(that.isCollapsed));
}
},
gridnav: {
autofocusInput: false,
handleCursorKeys: true
},
filter: {
mode: 'hide',
autoApply: true
},
collapse: function(event, data) {
if (that.isCollapsed[data.node.key]) return;
that.isCollapsed[data.node.key] = true;
that.main.saveConfig('adaptersIsCollapsed', JSON.stringify(that.isCollapsed));
}
});
that.$tab.find('#btn_collapse_adapters').show().off('click').on('click', function () {
that.$tab.find('.process-adapters').show();
setTimeout(function () {
that.$grid.fancytree('getRootNode').visit(function (node) {
if (!that.filterVals.length || node.match || node.subMatch) node.setExpanded(false);
});
that.$tab.find('.process-adapters').hide();
}, 100);
});
that.$tab.find('#btn_expand_adapters').show().off('click').on('click', function () {
that.$tab.find('.process-adapters').show();
setTimeout(function () {
that.$grid.fancytree('getRootNode').visit(function (node) {
if (!that.filterVals.length || node.match || node.subMatch)
node.setExpanded(true);
});
that.$tab.find('.process-adapters').hide();
}, 100);
});
that.$tab.find('#btn_list_adapters').show().off('click').on('click', function () {
var $processAdapters = that.$tab.find('.process-adapters');
$processAdapters.show();
that.isList = !that.isList;
if (that.isList) {
that.$tab.find('#btn_list_adapters').addClass('red lighten-3');
that.$tab.find('#btn_expand_adapters').hide();
that.$tab.find('#btn_collapse_adapters').hide();
$(this).attr('title', _('list'));
} else {
that.$tab.find('#btn_list_adapters').removeClass('red lighten-3');
that.$tab.find('#btn_expand_adapters').show();
that.$tab.find('#btn_collapse_adapters').show();
$(this).attr('title', _('tree'));
}
that.main.saveConfig('adaptersIsList', that.isList);
$processAdapters.show();
setTimeout(function () {
that._postInit(true);
$processAdapters.hide();
}, 200);
});
} else {
that.$tab.find('#btn_collapse_adapters').show();
that.$tab.find('#btn_expand_adapters').show();
that.$tab.find('#btn_list_adapters').show();
}
if (that.isList) {
that.$tab.find('#btn_list_adapters').addClass('red lighten-3').attr('title', _('tree'));
that.$tab.find('#btn_expand_adapters').hide();
that.$tab.find('#btn_collapse_adapters').hide();
} else {
that.$tab.find('#btn_list_adapters').removeClass('red lighten-3').attr('title', _('list'));
that.$tab.find('#btn_expand_adapters').show();
that.$tab.find('#btn_collapse_adapters').show();
}
that.$tab.find('.filter-input').trigger('change');
}
function prepareTiles() {
that.$grid.hide();
that.$tiles.show();
that.$tab.find('#main-toolbar-table-types-btn').show();
that.$tab.find('#btn_list_adapters').hide();
that.$tab.find('#btn_collapse_adapters').hide();
that.$tab.find('#btn_expand_adapters').hide();
that.$tab.find('.filter-input').trigger('change');
}
function onOnlyUpdatableChanged() {
if (that.onlyUpdatable) {
that.$tab.find('#btn_filter_updates').addClass('red lighten-3');
that.$tab.find('#btn_upgrade_all').show();
} else {
that.$tab.find('#btn_upgrade_all').hide();
that.$tab.find('#btn_filter_updates').removeClass('red lighten-3');
}
}
function onExpertmodeChanged() {
if (that.main.config.expertMode) {
that.$tab.find('#btn_adapters_expert_mode').addClass('red lighten-3');
that.$tab.find('#btn_upgrade_all').show();
} else {
that.$tab.find('#btn_adapters_expert_mode').removeClass('red lighten-3');
onOnlyUpdatableChanged();
}
}
function filterTiles() {
var anyVisible = false;
// filter
if (that.currentFilter) {
that.$tiles.find('.tile').each(function () {
var $this = $(this);
if (that.currentType && !$this.hasClass('class-' + that.currentType)) {
$this.hide();
return;
}
if (customFilter({key: $this.data('id')})) {
anyVisible = true;
$this.show();
} else {
$this.hide();
}
});
} else {
if (!that.currentType) {
that.$tiles.find('.tile')
.show()
.each(function () {
if ($(this).is(':visible')) {
anyVisible = true;
return false;
}
});
} else {
that.$tiles.find('.tile').hide();
that.$tiles.find('.class-' + that.currentType).show();
that.$tiles.find('.tile').each(function () {
if ($(this).is(':visible')) {
anyVisible = true;
return false;
}
});
}
}
if (anyVisible) {
that.$tiles.find('.filtered-out').hide();
} else {
that.$tiles.find('.filtered-out').show();
}
}
this.prepare = function () {
this.$tab.find('#btn_switch_adapters').off('click').on('click', function () {
that.$tab.find('.process-adapters').show();
that.isTiles = !that.isTiles;
if (that.isTiles) {
that.$tab.removeClass('view-table').addClass('view-tiles');
$(this).find('i').text('view_list');
} else {
$(this).find('i').text('view_module');
that.$tab.removeClass('view-tiles').addClass('view-table');
}
that.main.saveConfig('adaptersIsTiles', that.isTiles);
setTimeout(function () {
if (that.isTiles) {
prepareTiles();
} else {
prepareTable();
}
that._postInit(true);
that.$tab.find('.process-adapters').hide();
}, 50);
});
this.$tab.find('#btn_filter_adapters').off('click').on('click', function () {
that.$tab.find('.process-adapters').show();
that.onlyInstalled = !that.onlyInstalled;
if (that.onlyInstalled) {
that.$tab.find('#btn_filter_adapters').addClass('red lighten-3');
} else {
that.$tab.find('#btn_filter_adapters').removeClass('red lighten-3');
}
that.main.saveConfig('adaptersOnlyInstalled', that.onlyInstalled);
setTimeout(function () {
that._postInit(true);
that.$tab.find('.process-adapters').hide();
}, 50);
});
this.$tab.find('#btn_filter_updates').off('click').on('click', function () {
that.$tab.find('.process-adapters').show();
that.onlyUpdatable = !that.onlyUpdatable;
onOnlyUpdatableChanged();
that.main.saveConfig('adaptersOnlyUpdatable', that.onlyUpdatable);
setTimeout(function () {
that._postInit(true);
that.$tab.find('.process-adapters').hide();
}, 200);
});
this.$tab.find('#btn_filter_custom_url')
.off('click')
.on('click', function () {
// prepare adapters
var text = '';
var order = [];
var url;
for (url in that.urls) {
if (that.urls.hasOwnProperty(url)) {
order.push(url);
}
}
order.sort();
for (var o = 0; o < order.length; o++) {
var user = that.urls[order[o]].match(/\.com\/([-_$§A-Za-z0-9]+)\/([-._$§A-Za-z0-9]+)\//);
if (user && user.length >= 2 && (that.main.config.expertMode || order[o].indexOf('js-controller') === -1)) {
text += '';
}
}
that.$installDialog.find('#install-github-link').html(text).val(that.main.config.adaptersGithub || '');
that.$installDialog.modal();
that.$installDialog.find('.btn-install').off('click').on('click', function () {
var isCustom = !that.$installDialog.find('a[href="#tabs-install-github"]').hasClass('active');//!!that.$installDialog.find('#tabs-install').tabs('option', 'active');
var url;
var debug;
var adapter;
if (isCustom) {
url = that.$installDialog.find('#install-url-link').val();
if (url.startsWith("http") && url.endsWith(".git") url = "git+" _ url;
debug = that.$installDialog.find('#install-url-debug').prop('checked') ? ' --debug' : '';
adapter = '';
} else {
var parts = that.$installDialog.find('#install-github-link').val().split(' ');
url = parts[0];
debug = that.$installDialog.find('#install-github-debug').prop('checked') ? ' --debug' : '';
adapter = ' ' + parts[1];
}
if (!url) {
that.main.showError(_('Invalid link'));
return;
}
that.main.cmdExec(null, 'url "' + url + '"' + adapter + debug, function (exitCode) {
if (!exitCode) {
that.init(true, true);
}
});
});
that.$installDialog.find('#install-github-link').select();
// workaround for materialize checkbox problem
that.$installDialog.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');
}
});
that.$installDialog.modal('open');
that.$installDialog.find('.tabs').mtabs({
nShow: function (tab) {
if (!tab) return;
that.main.saveConfig('adaptersInstallTab', $(tab).attr('id'));
}
});
if (that.main.config.adaptersInstallTab && !that.main.noSelect) {
that.$installDialog.find('.tabs').mtabs('select', that.main.config.adaptersInstallTab);
}
});
this.$tab.find('#btn_upgrade_all').off('click').on('click', function () {
that.main.confirmMessage(_('Do you want to upgrade all adapters?'), _('Please confirm'), 'help', function (result) {
if (result) {
that.main.cmdExec(null, 'upgrade', function (exitCode) {
if (!exitCode) that._postInit(true);
});
}
});
});
this.$tab.find('#btn_adapters_expert_mode').on('click', function () {
that.main.config.expertMode = !that.main.config.expertMode;
that.main.saveConfig('expertMode', that.main.config.expertMode);
that.updateExpertMode();
that.main.tabs.instances.updateExpertMode();
});
if (that.main.config.expertMode) {
that.$tab.find('#btn_adapters_expert_mode').addClass('red lighten-3');
}
// save last selected adapter
this.$installDialog.find('#install-github-link').on('change', function () {
that.main.saveConfig('adaptersGithub', $(this).val());
});
this.$installDialog.find('#install-url-link').on('keyup', function (event) {
if (event.which === 13) {
that.$installDialog.find('#dialog-install-url-button').trigger('click');
}
});
// Load settings
this.isTiles = (this.main.config.adaptersIsTiles !== undefined && this.main.config.adaptersIsTiles !== null) ? this.main.config.adaptersIsTiles : true;
this.isList = this.main.config.adaptersIsList || false;
this.onlyInstalled = this.main.config.adaptersOnlyInstalled || false;
this.onlyUpdatable = this.main.config.adaptersOnlyUpdatable || false;
this.currentFilter = this.main.config.adaptersCurrentFilter || '';
this.currentType = this.main.config.adaptersCurrentType || '';
this.currentOrder = this.main.config.adaptersCurrentOrder || 'a-z';
this.isCollapsed = this.main.config.adaptersIsCollapsed ? JSON.parse(this.main.config.adaptersIsCollapsed) : {};
if (this.currentFilter) {
this.$tab.find('.filter-input').addClass('input-not-empty').val(that.currentFilter);
this.$tab.find('.filter-clear').show();
} else {
this.$tab.find('.filter-clear').hide();
}
if (this.onlyInstalled) {
this.$tab.find('#btn_filter_adapters').addClass('red lighten-3');
} else {
this.$tab.find('#btn_filter_adapters').removeClass('red lighten-3');
}
if (this.onlyUpdatable) {
this.$tab.find('#btn_filter_updates').addClass('red lighten-3');
} else {
this.$tab.find('#btn_filter_updates').removeClass('red lighten-3');
}
// fix for IE
if (this.main.browser === 'ie' && this.main.browserVersion <= 10) {
this.isTiles = false;
this.$tab.find('#btn_switch_adapters').hide();
}
onExpertmodeChanged();
this.$tab.find('#btn_refresh_adapters').on('click', function () {
that.init(true, true);
});
// add filter processing
this.$tab.find('.filter-input').on('keyup', function () {
$(this).trigger('change');
}).on('change', function (event) {
if (that.filterTimer) {
clearTimeout(that.filterTimer);
}
that.filterTimer = setTimeout(function () {
that.filterTimer = null;
that.currentFilter = that.$tab.find('.filter-input').val().toLowerCase();
event && event.target && $(event.target)[that.currentFilter ? 'addClass' : 'removeClass']('input-not-empty');
if (that.currentFilter) {
that.$tab.find('.filter-clear').show();
} else {
that.$tab.find('.filter-clear').hide();
}
that.main.saveConfig('adaptersCurrentFilter', that.currentFilter);
if (that.isTiles) {
filterTiles();
} else {
that.$grid.fancytree('getTree').filterNodes(customFilter, false);
}
}, 400);
});
this.$tab.find('.filter-clear').on('click', function () {
that.$tab.find('.filter-input').val('').trigger('change');
});
if (this.isTiles) {
this.$tab.find('#btn_switch_adapters').find('i').text('view_list');
that.$tab.removeClass('view-table').addClass('view-tiles');
prepareTiles();
} else {
that.$tab.removeClass('view-tiles').addClass('view-table');
prepareTable();
}
};
this.updateExpertMode = function () {
this.init(true);
onExpertmodeChanged();
};
function customFilter(node) {
//if (node.parent && node.parent.match) return true;
if (that.currentFilter) {
if (!that.data[node.key]) return false;
var title = that.data[node.key].title;
if (title && typeof title === 'object') {
title = title[systemLang] || title.en;
}
var desc = that.data[node.key].desc;
if (desc && typeof desc === 'object') {
desc = desc[systemLang] || desc.en;
}
if ((that.data[node.key].name && that.data[node.key].name.toLowerCase().indexOf(that.currentFilter) !== -1) ||
(title && title.toLowerCase().indexOf(that.currentFilter) !== -1) ||
(that.data[node.key].keywords && that.data[node.key].keywords.toLowerCase().indexOf(that.currentFilter) !== -1) ||
(desc && desc.toLowerCase().indexOf(that.currentFilter) !== -1)){
return true;
} else {
return false;
}
} else {
return true;
}
}
this.getAdaptersInfo = function (host, update, updateRepo, callback) {
if (!host) return;
if (!callback) throw 'Callback cannot be null or undefined';
if (update) {
// Do not update too often
if (!this.curRepoLastUpdate || ((new Date()).getTime() - this.curRepoLastUpdate > 1000)) {
this.curRepository = null;
this.curInstalled = null;
}
}
if (this.curRunning) {
this.curRunning.push(callback);
return;
}
if (!this.curRepository || this.curRepoLastHost !== host) {
this.curRepository = null;
this.main.socket.emit('sendToHost', host, 'getRepository', {repo: this.main.systemConfig.common.activeRepo, update: updateRepo}, function (_repository) {
if (_repository === 'permissionError') {
console.error('May not read "getRepository"');
_repository = {};
}
that.curRepository = _repository || {};
if (that.curRepository && that.curInstalled && that.curRunning) {
that.curRepoLastUpdate = (new Date()).getTime();
setTimeout(function () {
for (var c = 0; c < that.curRunning.length; c++) {
that.curRunning[c](that.curRepository, that.curInstalled);
}
that.curRunning = null;
}, 0);
}
});
}
if (!this.curInstalled || this.curRepoLastHost !== host) {
this.curInstalled = null;
this.main.socket.emit('sendToHost', host, 'getInstalled', null, function (_installed) {
if (_installed === 'permissionError') {
console.error('May not read "getInstalled"');
_installed = {};
}
that.curInstalled = _installed || {};
if (that.curRepository && that.curInstalled) {
that.curRepoLastUpdate = (new Date()).getTime();
setTimeout(function () {
for (var c = 0; c < that.curRunning.length; c++) {
that.curRunning[c](that.curRepository, that.curInstalled);
}
that.curRunning = null;
}, 0);
}
});
}
this.curRepoLastHost = host;
if (this.curInstalled && this.curRepository) {
setTimeout(function () {
if (that.curRunning) {
for (var c = 0; c < that.curRunning.length; c++) {
that.curRunning[c](that.curRepository, that.curInstalled);
}
that.curRunning = null;
}
if (callback) callback(that.curRepository, that.curInstalled);
}, 0);
} else {
this.curRunning = [callback];
}
};
this.enableColResize = function () {
if (!$.fn.colResizable) return;
if (this.$grid.is(':visible')) {
this.$grid.colResizable({liveDrag: true});
}
};
function getNews(actualVersion, adapter) {
var text = '';
if (adapter.news) {
for (var v in adapter.news) {
if (adapter.news.hasOwnProperty(v)) {
if (systemLang === v) text += (text ? '\n' : '') + adapter.news[v];
if (v === 'en' || v === 'cn') continue;
if (v === actualVersion) break;
text += (text ? '\n' : '') + (adapter.news[v][systemLang] || adapter.news[v].en);
}
}
}
return text;
}
function checkDependencies(dependencies) {
if (!dependencies) return '';
// like [{"js-controller": ">=0.10.1"}]
var adapters;
if (dependencies instanceof Array) {
adapters = {};
for (var a = 0; a < dependencies.length; a++) {
if (typeof dependencies[a] === 'string') continue;
for (var b in dependencies[a]) {
if (dependencies[a].hasOwnProperty(b)) {
adapters[b] = dependencies[a][b];
}
}
}
} else {
adapters = dependencies;
}
for (var adapter in adapters) {
if (adapters.hasOwnProperty(adapter)) {
if (adapter === 'js-controller') {
if (!semver.satisfies(that.main.objects['system.host.' + that.main.currentHost].common.installedVersion, adapters[adapter])) return _('Invalid version of %s. Required %s', adapter, adapters[adapter]);
} else {
if (!that.main.objects['system.adapter.' + adapter] || !that.main.objects['system.adapter.' + adapter].common || !that.main.objects['system.adapter.' + adapter].common.installedVersion) return _('No version of %s', adapter);
if (!semver.satisfies(that.main.objects['system.adapter.' + adapter].common.installedVersion, adapters[adapter])) return _('Invalid version of %s', adapter);
}
}
}
return '';
}
this.sortTree = function() {
function sort(c1, c2) {
//var d1 = that.data[c1.key], d2 = that.data[c1.key];
var inst1 = c1.data.installed || 0, inst2 = c2.data.installed || 0;
var ret = inst2 - inst1;
if (ret) return ret;
var t1 = c1.titleLang || c1.title || '';
if (typeof t1 === 'object') {
t1 = t1[systemLang] || t1.en;
}
var t2 = c2.titleLang || c2.title || '';
if (typeof t2 === 'object') {
t2 = t2[systemLang] || t2.en;
}
t1 = t1.toLowerCase();
t2 = t2.toLowerCase();
if (t1 > t2) return 1;
if (t1 < t2) return -1;
return 0;
}
that.$grid.fancytree('getRootNode').sortChildren(sort, true);
};
function getInterval(time, todayText, yesterdayText, x1DayAgoText, x2DaysAgoText, x5DaysAgoText, now) {
now = now || Date.now();
if (!time) return '';
if (typeof time === 'string' || typeof time === 'number') {
time = new Date(time);
}
var interval = now.getTime() - time.getTime();
var days = Math.floor(interval / (24 * 3600000));
if (days === 0) {
if (now.getDate() === time.getDate()) {
return todayText;
} else {
return yesterdayText;
}
} else if (days === 1) {
if (now.getDate() - time.getDate() === 1) {
return yesterdayText;
} else {
return x2DaysAgoText.replace('%d', days + 1);
}
} else {
var t = days % 10;
var tt = days % 100;
// 2, 3, 4, 22, 23, 24, 32, 33, 34, 111, ...x2, x3, h4
if ((tt < 10 || tt > 20) && t >= 2 && t <= 4) {
return x2DaysAgoText.replace('%d', days);
} else
// 1, 21, 31, 41, 121....
if ((tt < 10 || tt > 20) && t === 1) {
return x1DayAgoText.replace('%d', days);
} else {
return x5DaysAgoText.replace('%d', days);
}
}
}
this._postInit = function (update, updateRepo) {
if (typeof this.$grid !== 'undefined') {
that.$tab.find('.process-adapters').show();
this.$grid.find('tbody').html('');
this.getAdaptersInfo(this.main.currentHost, update, updateRepo, function (repository, installedList) {
var obj;
var version;
var rawVersion;
var adapter;
var adaptersToUpdate = 0;
var listInstalled = [];
var listNonInstalled = [];
var nowObj = new Date();
var localTexts = {
'add instance': _('add instance'),
'update': _('update'),
'upload': _('upload'),
'Available version:': _('Available version:'),
'Active instances': _('Active instances'),
'Installed version': _('Installed version'),
'readme': _('readme'),
'delete adapter': _('delete adapter'),
'install specific version': _('install specific version'),
'all': _('all'),
'Last update': _('Last update'),
'Installations counter': _('Installation counter'),
'today': _('today'),
'yesterday': _('yesterday'),
'1 %d days ago': _('1 %d days ago'),
'2 %d days ago': _('2 %d days ago'),
'5 %d days ago': _('5 %d days ago')
};
if (installedList) {
for (adapter in installedList) {
if (!installedList.hasOwnProperty(adapter)) continue;
obj = installedList[adapter];
if (!obj || obj.controller || adapter === 'hosts') continue;
listInstalled.push(adapter);
}
listInstalled.sort();
}
that.urls = {};
// List of adapters for repository
for (adapter in repository) {
if (!repository.hasOwnProperty(adapter)) continue;
if (installedList && installedList[adapter] && !installedList[adapter].versionDate) {
installedList[adapter].versionDate = repository[adapter].versionDate;
}
// it is not possible to install this adapter from git
if (!repository[adapter].nogit) {
that.urls[adapter] = repository[adapter].meta;
}
obj = repository[adapter];
if (!obj || obj.controller) continue;
version = '';
if (installedList && installedList[adapter]) continue;
listNonInstalled.push(adapter);
}
listNonInstalled.sort();
function getVersionString(version, updatable, news, updatableError) {
//var span = getVersionSpan(version);
var color = getVersionClass(version);
var title = color + '\n\r' + (news || '');
//version = '
' +
version = //'
' +
'
' +
'
' +
'
' + version + '
' +
'
';
if (updatable) { //xxx
version += '';
}
version += '
';
return version;
}
that.tree = [];
that.data = {};
// list of the installed adapters
for (var i = 0; i < listInstalled.length; i++) {
adapter = listInstalled[i];
obj = installedList ? installedList[adapter] : null;
if (!obj || obj.controller || adapter === 'hosts') continue;
var installed = '';
var rawInstalled = '';
var icon = obj.icon;
version = '';
if (repository[adapter] && repository[adapter].version) version = repository[adapter].version;
if (repository[adapter] && repository[adapter].extIcon) icon = repository[adapter].extIcon;
var _instances = 0;
var _enabled = 0;
if (obj.version) {
var news = '';
var updatable = false;
var updatableError = '';
if (!that.main.upToDate(version, obj.version)) {
news = getNews(obj.version, repository[adapter]);
// check if version is compatible with current adapters and js-controller
updatable = true;
updatableError = checkDependencies(repository[adapter].dependencies);
adaptersToUpdate++;
}
// TODO: move style to class
installed = '
' +
'
';
// Show information about installed and enabled instances
for (var z = 0; z < that.main.instances.length; z++) {
if (that.main.objects[that.main.instances[z]] &&
that.main.objects[that.main.instances[z]].common.name === adapter) {
_instances++;
if (that.main.objects[that.main.instances[z]].common.enabled) _enabled++;
}
}
if (_instances) {
// TODO: move style to class
installed += '