mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Plugin system improvements.
This commit is contained in:
parent
73e3b669c8
commit
467349f347
18 changed files with 10962 additions and 411 deletions
File diff suppressed because one or more lines are too long
|
@ -55,6 +55,11 @@
|
|||
<div id="cxtermnorm" class="cmtext" onclick="cmtermaction(1,event)">Normal Connect</div>
|
||||
<div id="cxtermps" class="cmtext" onclick="cmtermaction(2,event)">PowerShell Connect</div>
|
||||
</div>
|
||||
<!--
|
||||
<div id="pluginTabContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
|
||||
<div id="cxclose" class="cmtext" onclick="pluginTabClose(event)">Close Tab</div>
|
||||
</div>
|
||||
-->
|
||||
<!-- main page -->
|
||||
<div id="container">
|
||||
<div id="notifiyBox" class="notifiyBox" style="display:none"></div>
|
||||
|
@ -107,6 +112,7 @@
|
|||
<td tabindex="0" id="MainMenuMyFiles" class="topbar_td style3x" onclick="go(5,event)" onkeypress="if (event.key == 'Enter') go(5)">Mes Dossiers</td>
|
||||
<td tabindex="0" id="MainMenuMyUsers" class="topbar_td style3x" onclick="go(4,event)" onkeypress="if (event.key == 'Enter') go(4)">Mes Utilisateurs</td>
|
||||
<td tabindex="0" id="MainMenuMyServer" class="topbar_td style3x" onclick="go(6,event)" onkeypress="if (event.key == 'Enter') go(6)">Mon Serveur</td>
|
||||
<!-- <td tabindex=0 id=MainMenuMyPlugins class="topbar_td style3x" onclick=go(7,event) onkeypress="if (event.key == 'Enter') go(7)">My Plugins</td> -->
|
||||
<td class="topbar_td_end style3"> </td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
@ -150,10 +156,20 @@
|
|||
<td tabindex="0" id="ServerStats" class="topbar_td style3x" onclick="go(40,event)" onkeypress="if (event.key == 'Enter') go(40)">Stats</td>
|
||||
<td tabindex="0" id="ServerConsole" class="topbar_td style3x" onclick="go(115,event)" onkeypress="if (event.key == 'Enter') go(115)">Console</td>
|
||||
<td tabindex="0" id="ServerTrace" class="topbar_td style3x" onclick="go(41,event)" onkeypress="if (event.key == 'Enter') go(41)">Trace</td>
|
||||
<td tabindex="0" id="ServerPlugins" class="topbar_td style3x" onclick="go(42,event)" onkeypress="if (event.key == 'Enter') go(42)">Plugins</td>
|
||||
<td class="topbar_td_end style3"> </td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</div>
|
||||
<!--
|
||||
<div id=PluginSubMenuSpan>
|
||||
<table id=PluginSubMenu cellpadding=0 cellspacing=0 class=style1>
|
||||
<tr>
|
||||
<td onclick="goPlugin(-1)" onkeypress="if (event.key == 'Enter') goPlugin(-1)" class="topbar_td style3x">Home</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
-->
|
||||
<div id="UserDummyMenuSpan">
|
||||
<table id="UserDummyMenu" cellpadding="0" cellspacing="0" class="style1">
|
||||
<tbody><tr><td class="style3" style=""> </td></tr>
|
||||
|
@ -847,6 +863,28 @@
|
|||
</div>
|
||||
<div id="p41events" style=""></div>
|
||||
</div>
|
||||
<div id="p42" style="display:none">
|
||||
<h1>My Server Plugins</h1>
|
||||
<div class="areaHead">
|
||||
<div class="toright2">
|
||||
</div>
|
||||
<div>
|
||||
<input value="Download Plugin" type="button" onclick="return pluginHandler.addPluginDlg();">
|
||||
</div>
|
||||
</div>
|
||||
<div id="pluginRestartNotice" class="areaHead" style="background-color:gold;display:none">
|
||||
<div class="toright2">
|
||||
<input value="Refresh Agent Cores" type="button" onclick="distributeCore();return false">
|
||||
</div>
|
||||
<div style="padding:2px">
|
||||
<div style="padding:2px"><b>Notice:</b> Plugins have been altered, this may require agent core update.</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="p42tbl">
|
||||
<tbody><tr class="DevSt"><th style="width:26px"></th><th style="width:10px"></th><th class="chName">Nom</th><th class="chDescription">Description</th><th class="chSite" style="text-align:center">Link</th><th class="chVersion" style="text-align:center">Version</th><th class="chUpgradeAvail" style="text-align:center">Latest</th><th class="chStatus" style="text-align:center">Statut</th><th class="chAction" style="text-align:center">Action</th><th style="width:10px"></th></tr>
|
||||
</tbody></table>
|
||||
<div id="pluginNoneNotice" style="width:100%;text-align:center;padding-top:10px;display:none"><i>No plugins on server.</i></div>
|
||||
</div>
|
||||
<div id="p19" style="display:none">
|
||||
<h1>Plugins - <span id="p19deviceName"></span></h1>
|
||||
<style>
|
||||
|
@ -1040,6 +1078,7 @@
|
|||
var pluginHandlerBuilder = {{{pluginHandler}}};
|
||||
var pluginHandler = null;
|
||||
if (pluginHandlerBuilder != null) { pluginHandler = new pluginHandlerBuilder(); }
|
||||
var installedPluginList = null;
|
||||
|
||||
// Console Message Display Timers
|
||||
var p11DeskConsoleMsgTimer = null;
|
||||
|
@ -1293,6 +1332,7 @@
|
|||
// Fetch list of meshes, nodes, files
|
||||
meshserver.send({ action: 'meshes' });
|
||||
meshserver.send({ action: 'nodes', id: '{{currentNode}}' });
|
||||
if (pluginHandler != null) { meshserver.send({ action: 'plugins' }); }
|
||||
if ('{{currentNode}}' == '') { meshserver.send({ action: 'files' }); }
|
||||
if ('{{viewmode}}' == '') { go(1); }
|
||||
authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
|
||||
|
@ -2282,6 +2322,16 @@
|
|||
//console.log(message.msg);
|
||||
break;
|
||||
}
|
||||
case 'updatePluginList': {
|
||||
installedPluginList = message.event.list;
|
||||
updatePluginList();
|
||||
break;
|
||||
}
|
||||
case 'pluginStateChange': {
|
||||
if (pluginHandler == null) break;
|
||||
pluginHandler.refreshPluginHandler();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
//console.log('Unknown message.event.action', message.event.action);
|
||||
break;
|
||||
|
@ -2335,6 +2385,27 @@
|
|||
QH('p0span', message.msg);
|
||||
break;
|
||||
}
|
||||
case 'updatePluginList': {
|
||||
installedPluginList = message.list;
|
||||
updatePluginList();
|
||||
break;
|
||||
}
|
||||
case 'pluginVersionsAvailable': {
|
||||
if (pluginHandler == null) break;
|
||||
updatePluginList(message.list);
|
||||
break;
|
||||
}
|
||||
case 'downgradePluginVersions': {
|
||||
var vSelect = '<select id="lastPluginVersion">';
|
||||
message.info.versionList.forEach(function(v) { vSelect += '<option value="' + v.zipball_url + '">' + v.name + '</option>'; });
|
||||
vSelect += '</select>';
|
||||
setDialogMode(2, "Plugin Action", 3, pluginActionEx, format('Select the version to downgrade the plugin: {0}', message.info.name) + '<hr />' + vSelect + '<hr />' + "Please be aware that downgrading is not recommended. Please only do so in the event that a recent upgrade has broken something." + + '<input id="lastPluginAct" type="hidden" value="downgrade" /><input id="lastPluginId" type="hidden" value="' + message.info.id + '" />');
|
||||
break;
|
||||
}
|
||||
case 'pluginError': {
|
||||
setDialogMode(2, "Plugin Error", 1, null, message.msg);
|
||||
break;
|
||||
}
|
||||
case 'plugin': {
|
||||
if ((pluginHandler == null) || (typeof message.plugin != 'string')) break;
|
||||
try { pluginHandler[message.plugin][message.method](server, message); } catch (e) { console.log('Error loading plugin handler ('+ e + ')'); }
|
||||
|
@ -3482,6 +3553,12 @@
|
|||
contextmenudiv.style.left = event.pageX + 'px';
|
||||
contextmenudiv.style.top = event.pageY + 'px';
|
||||
contextmenudiv.style.display = 'block';
|
||||
/*} else if (elem && elem != null && elem.classList.contains('pluginTab')) {
|
||||
contextelement = elem;
|
||||
var contextmenudiv = document.getElementById('pluginTabContextMenu');
|
||||
contextmenudiv.style.left = event.pageX + 'px';
|
||||
contextmenudiv.style.top = event.pageY + 'px';
|
||||
contextmenudiv.style.display = 'block';*/
|
||||
} else {
|
||||
while (elem && elem != null && elem.id != 'devs') { elem = elem.parentElement; }
|
||||
if (!elem || elem == null) return true;
|
||||
|
@ -3553,10 +3630,23 @@
|
|||
connectTerminal(null, 1, { powershell: (action == 2) });
|
||||
}
|
||||
|
||||
/*
|
||||
function pluginTabClose() {
|
||||
var pluginTab = contextelement;
|
||||
var pname = pluginTab.getAttribute('x-data-plugin-sname');
|
||||
var pdiv = Q('plugin-'+pname);
|
||||
pdiv.parentNode.removeChild(pdiv);
|
||||
pluginTab.parentNode.removeChild(pluginTab);
|
||||
QV('p42', true);
|
||||
goPlugin(-1);
|
||||
}
|
||||
*/
|
||||
|
||||
function hideContextMenu() {
|
||||
QV('contextMenu', false);
|
||||
QV('meshContextMenu', false);
|
||||
QV('termShellContextMenu', false);
|
||||
//QV('pluginTabContextMenu', false);
|
||||
contextelement = null;
|
||||
}
|
||||
|
||||
|
@ -4478,7 +4568,7 @@
|
|||
p13clearConsoleMsg();
|
||||
|
||||
// Device refresh plugin handler
|
||||
if (pluginHandler != null) { pluginHandler.onDeviceRefeshEnd(nodeid, panel, refresh, event); }
|
||||
if (pluginHandler != null) { pluginHandler.callHook('onDeviceRefreshEnd', nodeid, panel, refresh, event); }
|
||||
}
|
||||
setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
|
||||
if (!panel) panel = 10;
|
||||
|
@ -5139,6 +5229,7 @@
|
|||
desktop.Stop();
|
||||
webRtcDesktopReset();
|
||||
desktopNode = desktop = null;
|
||||
if (pluginHandler != null) { pluginHandler.callHook('onDesktopDisconnect'); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9285,7 +9376,7 @@
|
|||
if (xxcurrentView == x) return;
|
||||
|
||||
// Edit this line when adding a new screen
|
||||
for (var i = 0; i < 42; i++) { QV('p' + i, i == x); }
|
||||
for (var i = 0; i < 43; i++) { QV('p' + i, i == x); }
|
||||
xxcurrentView = x;
|
||||
|
||||
// Remove top bar selection
|
||||
|
@ -9304,7 +9395,7 @@
|
|||
|
||||
// Define class for Menu(s) as fully or semi active.
|
||||
var mainMenuActiveClass = (x < 9 ? 'fullselect' : 'semiselect');
|
||||
var leftMenuActiveClass = (x < 9 ? 'lbbuttonsel2' : 'lbbuttonsel');
|
||||
var leftMenuActiveClass = (((x < 9) || (x == 115) || (x == 40) || (x == 41) || (x == 42)) ? 'lbbuttonsel2' : 'lbbuttonsel');
|
||||
|
||||
// My Devices
|
||||
if (x == 1 || (x >= 10 && x < 20)) QC('MainMenuMyDevices').add(mainMenuActiveClass);
|
||||
|
@ -9328,21 +9419,21 @@
|
|||
|
||||
// My Server
|
||||
if ((x == 6) || (x == 115)) QC('MainMenuMyServer').add(mainMenuActiveClass);
|
||||
if ((x == 6) || (x == 115) || (x == 40)) QC('LeftMenuMyServer').add(leftMenuActiveClass);
|
||||
if ((x == 6) || (x == 115) || (x == 40) || (x == 41) || (x == 42)) QC('LeftMenuMyServer').add(leftMenuActiveClass);
|
||||
|
||||
// column_l max-height
|
||||
if (webPageStackMenu && (x >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
|
||||
|
||||
// If we are going to panel 0 in "full screen mode", hide the left bar.
|
||||
QV('topbar', x != 0);
|
||||
if ((x == 0) && (webPageFullScreen)) { QC('body').add("arg_hide"); }
|
||||
if ((x == 0) && (webPageFullScreen)) { QC('body').add('arg_hide'); }
|
||||
|
||||
QV('MainSubMenuSpan', x >= 10 && x < 20);
|
||||
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
|
||||
QV('MeshSubMenuSpan', x >= 20 && x < 30);
|
||||
QV('UserSubMenuSpan', x >= 30 && x < 40);
|
||||
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40 || x == 41);
|
||||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 17: 'MainDevInfo', 19: 'MainDevPlugins', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 41: 'ServerTrace', 115: 'ServerConsole' };
|
||||
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40 || x == 41 || x == 42);
|
||||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 17: 'MainDevInfo', 19: 'MainDevPlugins', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 41: 'ServerTrace', 42: 'ServerPlugins', 115: 'ServerConsole' };
|
||||
for (var i in panels) {
|
||||
QC(panels[i]).remove('style3x');
|
||||
QC(panels[i]).remove('style3sel');
|
||||
|
@ -9366,6 +9457,9 @@
|
|||
// Fetch the server timeline stats if needed
|
||||
if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); }
|
||||
|
||||
// MyServer Plugins
|
||||
if (x == 42) { refreshPluginLatest(); } // goPlugin(-1); QV('PluginSubMenuSpan', true); goPlugin(-1); } //else { noGoPlugin(); }
|
||||
|
||||
// Update the web page title
|
||||
if ((currentNode) && (x >= 10) && (x < 20)) {
|
||||
document.title = decodeURIComponent('{{{extitle}}}') + ' - ' + currentNode.name + ' - ' + meshes[currentNode.meshid].name;
|
||||
|
@ -9374,6 +9468,207 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Plugin
|
||||
function updatePluginList(versInfo) {
|
||||
if (Array.isArray(versInfo)) { versInfo.forEach(function(v) { updatePluginList(v); }); }
|
||||
QV('pluginNoneNotice', installedPluginList.length == 0);
|
||||
if (installedPluginList.length) {
|
||||
if (versInfo != null) {
|
||||
if (installedPluginList['version_info'] == null) installedPluginList['version_info'] = [];
|
||||
installedPluginList['version_info'][versInfo.id] = versInfo;
|
||||
}
|
||||
var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
|
||||
if (tr.length) {
|
||||
for (var i in Object.values(tr)) {
|
||||
tr[i].parentNode.removeChild(tr[i]);
|
||||
}
|
||||
}
|
||||
var statusMap = {
|
||||
0: {
|
||||
'text': 'Disabled',
|
||||
'color': '858483'
|
||||
},
|
||||
1: {
|
||||
'text': 'Installed',
|
||||
'color': '00aa00'
|
||||
}
|
||||
};
|
||||
var statusAvailability = {
|
||||
0: {
|
||||
'install': 'Install',
|
||||
'delete': 'Delete'
|
||||
},
|
||||
1: {
|
||||
'disable': 'Disable',
|
||||
'upgrade': 'Upgrade',
|
||||
// 'downgrade': 'Downgrade' // disabling until plugins have prior versions available for better testing
|
||||
}
|
||||
};
|
||||
var vers_not_compat = ` [ <span onclick="return setDialogMode(2, 'Compatibility Issue', 1, null, 'This plugin version is not compatible with your MeshCentral installation, please upgrade MeshCentral first.');" title="Version incompatible, please upgrade your MeshCentral installation first" style="cursor: pointer; color:red;"> ! </span> ]`;
|
||||
|
||||
var tbl = Q('p42tbl');
|
||||
installedPluginList.forEach(function(p){
|
||||
var cant_action = [];
|
||||
if (p.hasAdminPanel == true && p.status) {
|
||||
p.nameHtml = `<a onclick="return goPlugin('${p.shortName}', '${p.name}');">${p.name}</a>`;
|
||||
} else {
|
||||
p.nameHtml = p.name;
|
||||
}
|
||||
p.statusText = statusMap[p.status].text;
|
||||
p.statusColor = statusMap[p.status].color;
|
||||
|
||||
if (p.versionHistoryUrl == null) { cant_action.push('downgrade'); }
|
||||
if (!p.status) { p.version = ' - '; } // It isn't technically installed, so no version number
|
||||
p.upgradeAvail = "Checking...";
|
||||
if (installedPluginList['version_info'] != null && installedPluginList['version_info'][p._id] != null) {
|
||||
var vin = installedPluginList['version_info'][p._id];
|
||||
if (vin.hasUpdate) {
|
||||
p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
||||
} else {
|
||||
cant_action.push('upgrade');
|
||||
if (p.status) p.upgradeAvail = "Up to date";
|
||||
else p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
||||
}
|
||||
if (!vin.meshCentralCompat) {
|
||||
p.upgradeAvail += vers_not_compat;
|
||||
cant_action.push('install');
|
||||
cant_action.push('upgrade');
|
||||
}
|
||||
}
|
||||
|
||||
p.actions = '<select onchange="return pluginAction(this,\'' + p._id + '\');"><option value=""> --</option>';
|
||||
var entries = Object.entries(statusAvailability[p.status]);
|
||||
for (var k in entries) {
|
||||
if (cant_action.indexOf(k) === -1) {
|
||||
p.actions += '<option value="' + entries[k][0] + '">' + entries[k][1] + '</option>';
|
||||
}
|
||||
}
|
||||
p.actions += '</select>';
|
||||
|
||||
let tpl = `<td><img style=margin-top:3px src=images/plugin24.png></td><td class=gradTable1> </td><td class=gradTable2>${p.nameHtml}</td><td class=gradTable2>${p.description}</td><td class=gradTable2 style=text-align:center><a href="${p.homepage}" target="_blank">Home</a></td><td class=gradTable2 style=text-align:center>${p.version}</td><td style=text-align:center class="pluginUpgradeAvailable gradTable2">${p.upgradeAvail}</td><td class=gradTable2 style="text-align:center;color:#${p.statusColor}">${p.statusText}</td><td class="pluginAction gradTable2" style=text-align:center>${p.actions}</td><td class=gradTable3> </td>`;
|
||||
let tr = tbl.insertRow(-1);
|
||||
tr.innerHTML = tpl;
|
||||
tr.classList.add('p42tblRow');
|
||||
tr.setAttribute('data-id', p._id);
|
||||
tr.setAttribute('id', 'pluginRow-' + p._id);
|
||||
});
|
||||
} else {
|
||||
var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
|
||||
for (var i in Object.values(tr)) { tr[i].parentNode.removeChild(tr[i]); }
|
||||
}
|
||||
if (versInfo == null) refreshPluginLatest();
|
||||
}
|
||||
|
||||
function refreshPluginLatest() {
|
||||
meshserver.send({ action: 'pluginLatestCheck' });
|
||||
}
|
||||
|
||||
function distributeCore() {
|
||||
meshserver.send({ action: 'distributeCore', nodes: nodes }); // All nodes the user has access to
|
||||
QV('pluginRestartNotice', false);
|
||||
}
|
||||
|
||||
function pluginActionEx() {
|
||||
var act = Q('lastPluginAct').value, id = Q('lastPluginId').value, pVersUrl = Q('lastPluginVersion').value;
|
||||
|
||||
switch(act) {
|
||||
case 'upgrade':
|
||||
case 'install':
|
||||
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': false });
|
||||
break;
|
||||
case 'downgrade':
|
||||
Q('lastPluginVersion').querySelectorAll('option').forEach(function(opt) {
|
||||
if (opt.value == pVersUrl) pVers = opt.text;
|
||||
});
|
||||
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': { 'name': pVers, 'url': pVersUrl }});
|
||||
break;
|
||||
case 'delete':
|
||||
meshserver.send({ 'action': 'removeplugin', 'id': id });
|
||||
break;
|
||||
case 'disable':
|
||||
meshserver.send({ 'action': 'disableplugin', 'id': id });
|
||||
break;
|
||||
}
|
||||
QV('pluginRestartNotice', true);
|
||||
}
|
||||
|
||||
function pluginAction(elem, id) {
|
||||
if (elem.value == 'downgrade') {
|
||||
meshserver.send({ 'action': 'getpluginversions', 'id': id });
|
||||
} else {
|
||||
var plugin = null;
|
||||
for (var i in installedPluginList) { if (installedPluginList[i]._id == id) { plugin = installedPluginList[i]; } }
|
||||
setDialogMode(2, "Plugin Action", 3, pluginActionEx, format("Are you sure you want to {0} the plugin: {1}", elem.value, plugin.name) + '<input id="lastPluginAct" type="hidden" value="' + elem.value + '" /><input id="lastPluginId" type="hidden" value="' + id + '" /><input id="lastPluginVersion" type="hidden" value="" />');
|
||||
}
|
||||
elem.value = '';
|
||||
}
|
||||
|
||||
function goPlugin(pname, title) {
|
||||
/*
|
||||
let holder = Q('PluginSubMenu').querySelectorAll('tr')[0];
|
||||
let loadedPluginsTDs = holder.querySelectorAll('td');
|
||||
var found = false;
|
||||
loadedPluginsTDs.forEach((p) => {
|
||||
p.classList.remove('style3sel');
|
||||
p.classList.add('style3x');
|
||||
var tname = p.getAttribute('x-data-plugin-sname');
|
||||
if (tname != null) { Q('plugin-' + tname).style.display = 'none'; }
|
||||
if (tname == pname) {
|
||||
// show existing tab / content
|
||||
p.classList.remove('style3x');
|
||||
p.classList.add('style3sel');
|
||||
QS('p42').display = 'none';
|
||||
Q('plugin-'+tname).style.display = '';
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
if (pname == -1) { // Go home
|
||||
QV('p42', true);
|
||||
let homeTab = loadedPluginsTDs[0];
|
||||
homeTab.classList.add('style3sel');
|
||||
homeTab.classList.remove('style3x');
|
||||
found = true;
|
||||
}
|
||||
if (found) return;
|
||||
|
||||
Q('PluginSubMenu').style.display = 'block';
|
||||
let sif = document.createElement('td');
|
||||
sif.setAttribute('x-data-plugin-sname', pname);
|
||||
sif.classList.add('topbar_td');
|
||||
sif.classList.add('style3sel');
|
||||
sif.classList.add('pluginTab');
|
||||
sif.setAttribute('onclick', 'goPlugin("' + pname + '", "' + title + '")');
|
||||
sif.setAttribute('onkeypress', 'if (event.key == "Enter") goPlugin("' + pname + '", "' + title + '")');
|
||||
sif.innerHTML = title;
|
||||
holder.append(sif);
|
||||
|
||||
let dif = document.createElement('div');
|
||||
dif.setAttribute('id', 'plugin-'+pname);
|
||||
dif.classList.add('pluginContent');
|
||||
let pif = document.createElement('iframe');
|
||||
pif.src = '/pluginadmin.ashx?pin='+pname;
|
||||
pif.setAttribute('frameBorder', '0');
|
||||
pif.style.width = '100%';
|
||||
pif.style.height = '100%';
|
||||
pif.setAttribute('frameBorder', '0');
|
||||
dif.append(pif);
|
||||
let x = Q('column_l_bottomgap');
|
||||
x.parentNode.insertBefore(dif, x.previousSibling);
|
||||
QS('p42').display = 'none';
|
||||
*/
|
||||
}
|
||||
|
||||
function noGoPlugin(el) {
|
||||
/*
|
||||
QV('PluginSubMenuSpan', false);
|
||||
let loadedPluginsTDs = Q('PluginSubMenu').querySelectorAll('td');
|
||||
loadedPluginsTDs.forEach((p) => {
|
||||
var tname = p.getAttribute('x-data-plugin-sname');
|
||||
if (tname != null) Q('plugin-'+tname).style.display = 'none';
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
// Generic methods
|
||||
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
||||
function putstore(name, val) {
|
||||
|
@ -9434,7 +9729,7 @@
|
|||
function addDetailItem(title, value, state) { return '<div><span style=float:right>' + value + '</span><span>' + title + '</span></div>'; }
|
||||
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
||||
function nobreak(x) { return x.split(' ').join(' '); }
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue