Improved internals of web app content menu system.

Ylian Saint-Hilaire committed Feb 17, 2020 at 13:41 UTC 40c6cdc88a6a665498f70b978ad531a4f98d03f7
1 file changed +48 -57
views/default.handlebars
+48 -57
@@ -606,7 +606,7 @@
606 <div>
607 <div id="idx_termFullBtn2" onclick=deskToggleFull(event)>&nbsp;&#x2716;</div>
608 <input type="button" id="autoconnectbutton2" value="AutoConnect" onclick=autoConnectTerminal(event) onkeypress="return false" onkeydown="return false" style="display:none" />
609 - <span id="connectbutton2span"><input type="button" id="connectbutton2" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
609 + <span id="connectbutton2span"><input type="button" id="connectbutton2" cmenu="termConnectButton" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
610 <span id="connectbutton2hspan">&nbsp;<input type="button" id="connectbutton2h" value="HW Connect" title="Connect using Intel AMT hardware KVM" onclick=connectTerminal(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
611 <span id="disconnectbutton2span">&nbsp;<input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false" /></span>
612 &nbsp;<span id="termstatus">Disconnected</span><span id="termtitle"></span>
@@ -3018,7 +3018,7 @@
3018 var collapsed = CollapsedGroups[node.meshid];
3019 r += '<img class=collapseImage id=\"DevxColImg' + deviceHeaderId + '\" src=images/c' + ((collapsed === true)?'1':'2') + '.png height=8 width=8 style=margin-left:2px;margin-right:2px;cursor:pointer onclick=toggleCollapseGroup(\"' + deviceHeaderId + '\",\"' + node.meshid + '\",' + view + ')></img>'; // Collapse action
3020 }
3021 - r += '<span id=MxMESH tabindex=0 style=cursor:pointer onclick=gotoMesh("' + node.meshid + '") onkeypress="if (event.key==\'Enter\') gotoMesh(\'' + node.meshid + '\')">' + EscapeHtml(meshes[node.meshid].name) + '</span>' + getMeshActions(mesh2, meshrights) + '</div>';
3021 + r += '<span id=MxMESH cmenu=meshContextMenu tabindex=0 style=cursor:pointer onclick=gotoMesh("' + node.meshid + '") onkeypress="if (event.key==\'Enter\') gotoMesh(\'' + node.meshid + '\')">' + EscapeHtml(meshes[node.meshid].name) + '</span>' + getMeshActions(mesh2, meshrights) + '</div>';
3022 if (view == 2) { r += '</div>'; }
3023 current = node.meshid;
3024 displayedMeshes[current] = 1;
@@ -3062,7 +3062,7 @@
3062 var icon = node.icon;
3063 if ((!node.conn) || (node.conn == 0)) { icon += ' gray'; }
3064 if (view == 1) {
3065 - r += '<div id=devs onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=display:inline-block;width:' + deviceBoxWidth + 'px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox></div><div style=height:100%;cursor:pointer tabindex=0 onclick=gotoDevice(\'' + node._id + '\',null,null,event) onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',null,null,event)"><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 style=width:' + (deviceBoxWidth - 100) + 'px title="' + title + '">' + name + '</div><div>' + NodeStateStr(node) + '</div></div><div class=g2></div></div></div></div>';
3065 + r += '<div id=devs cmenu=devsContentMenu onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=display:inline-block;width:' + deviceBoxWidth + 'px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox></div><div style=height:100%;cursor:pointer tabindex=0 onclick=gotoDevice(\'' + node._id + '\',null,null,event) onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',null,null,event)"><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 style=width:' + (deviceBoxWidth - 100) + 'px title="' + title + '">' + name + '</div><div>' + NodeStateStr(node) + '</div></div><div class=g2></div></div></div></div>';
3066 } else if (view == 2) {
3067 var states = [];
3068 if (node.conn) {
@@ -3999,65 +3999,56 @@
3999
4000 var contextelement = null;
4001 function handleContextMenu(event) {
4002 + // When called, we look for elements with "cmenu=xxx" and show the right context menu for that element.
4003 hideContextMenu();
4004 var scrollLeft = (window.pageXOffset !== null) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
4005 var scrollTop = (window.pageYOffset !== null) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
4006 var elem = document.elementFromPoint(event.pageX - scrollLeft, event.pageY - scrollTop);
4006 - //console.log('handleContextMenu', scrollLeft, scrollTop, elem, elem.parentElement, elem.parentElement.parentElement);
4007 -
4008 - // Look for a file entry element
4009 - var fileElement = null, elx = elem;
4010 - while (elx && elx != null && elx.id != 'fileEntry') { elx = elx.parentElement; }
4011 - if (elx && (elx.id == 'fileEntry')) { fileElement = elx; }
4012 -
4013 - if (elem && elem != null && elem.id == 'rdpClickOnceLink' && currentNode && currentNode.agent && (currentNode.agent.id > 0) && (currentNode.agent.id < 5)) {
4014 - contextelement = elem;
4015 - var contextmenudiv = document.getElementById('altPortContextMenu');
4016 - showContextMenuDiv(contextmenudiv, event.pageX, event.pageY);
4017 - } else if (elem && elem != null && elem.id == 'connectbutton2' && currentNode && currentNode.agent && (currentNode.agent.id > 0) && (currentNode.agent.id < 5)) {
4018 - contextelement = elem;
4019 - var contextmenudiv = document.getElementById('termShellContextMenu');
4020 - showContextMenuDiv(contextmenudiv, event.pageX, event.pageY);
4021 - } else if (elem && elem != null && elem.id == 'connectbutton2' && currentNode && currentNode.agent && (currentNode.agent.id > 4)) {
4022 - contextelement = elem;
4023 - var contextmenudiv = document.getElementById('termShellContextMenuLinux');
4024 - showContextMenuDiv(contextmenudiv, event.pageX, event.pageY);
4025 - } else if (fileElement && currentNode) {
4026 - contextelement = fileElement;
4027 - var contextmenudiv = document.getElementById('filesContextMenu');
4028 - showContextMenuDiv(contextmenudiv, event.pageX, event.pageY);
4029 - } else if (elem && elem != null && elem.id == 'MxMESH') {
4030 - contextelement = elem;
4031 - var contextmenudiv = document.getElementById('meshContextMenu');
4032 - showContextMenuDiv(contextmenudiv, event.pageX, event.pageY);
4033 - /*} else if (elem && elem != null && elem.classList.contains('pluginTab')) {
4007 + while (elem && elem != null && elem.attributes.cmenu == null) { elem = elem.parentElement; } // Go up until element with context menu or root is reached.
4008 + if (elem == null) return true; // No "cmenu=xxx" found at the element that was clicked.
4009 + var cmenu = elem.attributes.cmenu.value;
4010 +
4011 + switch (cmenu) {
4012 + case 'termConnectButton': {
4013 + // Terminal connect button context menu
4014 + if ((currentNode == null) || (currentNode.agent == null)) return true;
4015 contextelement = elem;
4035 - var contextmenudiv = document.getElementById('pluginTabContextMenu');
4016 + var contextmenudiv = document.getElementById('termShellContextMenu'); // Windows options (Power Shell)
4017 + if (currentNode.agent.id > 4) { contextmenudiv = document.getElementById('termShellContextMenuLinux'); } // Non-Windows options
4018 + showContextMenuDiv(contextmenudiv, event.pageX, event.pageY);
4019 + break;
4020 + }
4021 + case 'devsContentMenu': {
4022 + // Device content menu
4023 + contextelement = elem;
4024 + var contextmenudiv = document.getElementById('contextMenu');
4025 showContextMenuDiv(contextmenudiv, event.pageX, event.pageY);
4037 - */
4038 - } else {
4039 - while (elem && elem != null && elem.id != 'devs') { elem = elem.parentElement; }
4040 - if (!elem || elem == null) return true;
4041 - contextelement = elem;
4042 - var contextmenudiv = document.getElementById('contextMenu');
4043 - showContextMenuDiv(contextmenudiv, event.pageX, event.pageY);
4044 -
4045 - // Get the node and set the menu options
4046 - var nodeid = contextelement.children[1].attributes.onclick.value;
4047 - var node = getNodeFromId(nodeid.substring(12, nodeid.length - 18));
4048 - var mesh = meshes[node.meshid];
4049 - var rights = GetNodeRights(node);
4050 - var consoleRights = ((rights & 16) != 0);
4051 -
4052 - // Check if we have terminal and file access
4053 - var terminalAccess = ((rights == 0xFFFFFFFF) || ((rights & 512) == 0));
4054 - var fileAccess = ((rights == 0xFFFFFFFF) || ((rights & 1024) == 0));
4026
4056 - QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((rights & 8) || (rights & 256)));
4057 - QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (rights & 8) && terminalAccess);
4058 - QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (rights & 8) && fileAccess);
4059 - QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (rights & 8));
4060 - QV('cxconsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (rights & 8));
4027 + // Get the node and set the menu options
4028 + var nodeid = contextelement.children[1].attributes.onclick.value;
4029 + var node = getNodeFromId(nodeid.substring(12, nodeid.length - 18));
4030 + var mesh = meshes[node.meshid];
4031 + var rights = GetNodeRights(node);
4032 + var consoleRights = ((rights & 16) != 0);
4033 +
4034 + // Check if we have terminal and file access
4035 + var terminalAccess = ((rights == 0xFFFFFFFF) || ((rights & 512) == 0));
4036 + var fileAccess = ((rights == 0xFFFFFFFF) || ((rights & 1024) == 0));
4037 +
4038 + QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((rights & 8) || (rights & 256)));
4039 + QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (rights & 8) && terminalAccess);
4040 + QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (rights & 8) && fileAccess);
4041 + QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (rights & 8));
4042 + QV('cxconsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (rights & 8));
4043 + break;
4044 + }
4045 + default: {
4046 + // Basic context menu
4047 + if ((contextmenudiv = document.getElementById(cmenu)) == null) return true;
4048 + contextelement = elem;
4049 + showContextMenuDiv(contextmenudiv, event.pageX, event.pageY);
4050 + break;
4051 + }
4052 }
4053 return haltEvent(event);
4054 }
@@ -4989,7 +4980,7 @@
4980
4981 // RDP link, show this link only of the remote machine is Windows.
4982 if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) {
4992 - if ((node.agent.id > 0) && (node.agent.id < 5)) { x += '<a href=# id=rdpClickOnceLink onclick=p10clickOnce("' + node._id + '","RDP2",3389) title=\"' + "Requires Microsoft ClickOnce support in your browser" + '.\">' + "RDP" + '</a>&nbsp;'; }
4983 + if ((node.agent.id > 0) && (node.agent.id < 5)) { x += '<a href=# cmenu=altPortContextMenu id=rdpClickOnceLink onclick=p10clickOnce("' + node._id + '","RDP2",3389) title=\"' + "Requires Microsoft ClickOnce support in your browser" + '.\">' + "RDP" + '</a>&nbsp;'; }
4984 if (node.agent.id > 4) {
4985 x += '<a href=# onclick=p10clickOnce("' + node._id + '","PSSH",22) title=\"' + "Requires Microsoft ClickOnce support in your browser." + '\">' + "Putty" + '</a>&nbsp;';
4986 x += '<a href=# onclick=p10clickOnce("' + node._id + '","WSCP",22) title=\"' + "Requires Microsoft ClickOnce support in your browser." + '\">' + "WinSCP" + '</a>&nbsp;';
@@ -6847,7 +6838,7 @@
6838 } else {
6839 var link = shortname;
6840 if (f.s > 0) { link = '<a hrf=# rel=\"noreferrer noopener\" target=\"_blank\" style=cursor:pointer onclick=\"return p13downloadfile(\'' + encodeURIComponent(newlinkpath + '/' + name) + '\',\'' + encodeURIComponent(name) + '\',' + f.s + ')\">' + shortname + '</a>'; }
6850 - h = '<div id=fileEntry fileIndex=' + i + ' class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'>&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
6841 + h = '<div id=fileEntry cmenu=filesContextMenu fileIndex=' + i + ' class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'>&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
6842 }
6843
6844 if (f.t < 3) { html1 += h; } else { html2 += h; }