diff --git a/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js b/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js index cfb750012c..a0f5b62b23 100644 --- a/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js +++ b/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js @@ -6,6 +6,56 @@ function displayWebUI(url) { window.open(url, '_blank').focus(); } +function clampVMContextDropdownToViewport(id) { + var $dropdown = $('#dropdown-'+id); + if (!$dropdown.length) return; + + var scrollTop = $(window).scrollTop(); + var viewportTop = scrollTop + 8; + var viewportBottom = scrollTop + window.innerHeight - 8; + var menuHeight = $dropdown.outerHeight(); + var top = parseFloat($dropdown.css('top')); + + if (isNaN(top)) { + top = $dropdown.offset().top || viewportTop; + } + + if (top < viewportTop) { + top = viewportTop; + } + if (top + menuHeight > viewportBottom) { + top = Math.max(viewportTop, viewportBottom - menuHeight); + } + + $dropdown.css('top', top); +} + +function applyVMContextDropdownFix(id, selector) { + var $dropdown = $('#dropdown-'+id); + if (!$dropdown.length) return; + + $dropdown.css({ + 'z-index': 10001, + 'max-height': '', + 'overflow-y': '', + 'overflow-x': '' + }); + if (!$dropdown.children('.docker-dropdown-spacer').length) { + $dropdown.append(''); + } + + if (selector) { + $(document) + .off('click.vmcontextfix contextmenu.vmcontextfix', selector) + .on('click.vmcontextfix contextmenu.vmcontextfix', selector, function() { + setTimeout(function() { + applyVMContextDropdownFix(id); + clampVMContextDropdownToViewport(id); + }, 0); + }); + } +} + function downloadFile(source) { var a = document.createElement('a'); a.setAttribute('href',source); @@ -125,7 +175,7 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, f } } if (rundivider) opts.push({divider:true}); - context.settings({right:false,above:false}); + context.settings({right:false,above:'auto'}); if (state == "running") { opts.push({text:_("Stop"), icon:"fa-stop", action:function(e) { e.preventDefault(); @@ -251,7 +301,15 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, f }); }}); } - if (usage) { context.destroy('#vmusage-'+uuid); context.attach('#vmusage-'+uuid, opts); } else { context.destroy('#vm-'+uuid); context.attach('#vm-'+uuid, opts); } + if (usage) { + context.destroy('#vmusage-'+uuid); + context.attach('#vmusage-'+uuid, opts); + applyVMContextDropdownFix('vmusage-'+uuid, '#vmusage-'+uuid); + } else { + context.destroy('#vm-'+uuid); + context.attach('#vm-'+uuid, opts); + applyVMContextDropdownFix('vm-'+uuid, '#vm-'+uuid); + } } function addVMSnapContext(name, uuid, template, state, snapshotname, method){ var opts = []; @@ -259,7 +317,7 @@ function addVMSnapContext(name, uuid, template, state, snapshotname, method){ var x = path.indexOf("?"); if (x!=-1) path = path.substring(0,x); - context.settings({right:false,above:false}); + context.settings({right:false,above:'auto'}); opts.push({text:_("Revert snapshot"), icon:"fa-fast-backward", action:function(e) { @@ -287,6 +345,7 @@ function addVMSnapContext(name, uuid, template, state, snapshotname, method){ }}); context.destroy('#vmsnap-'+uuid); context.attach('#vmsnap-'+uuid, opts); + applyVMContextDropdownFix('vmsnap-'+uuid, '#vmsnap-'+uuid); } function startAll() { $('input[type=button]').prop('disabled',true);