Allow moving the controlbar handle
This also adds emulation of Element.setCapture() as only Firefox and Internet Explorer/Edge currently supports it.
This commit is contained in:
parent
65e3d7d6a6
commit
04b399e27d
|
@ -178,7 +178,8 @@ input[type=button]:active, select:active {
|
|||
#noVNC_control_bar_handle {
|
||||
position: absolute;
|
||||
right: -15px;
|
||||
top: 10%;
|
||||
top: 0;
|
||||
transform: translateY(35px);
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
z-index: -2;
|
||||
|
|
113
app/ui.js
113
app/ui.js
|
@ -43,6 +43,10 @@ var UI;
|
|||
hideKeyboardTimeout: null,
|
||||
controlbarTimeout: null,
|
||||
|
||||
controlbarGrabbed: false,
|
||||
controlbarDrag: false,
|
||||
controlbarMouseDownClientY: 0,
|
||||
controlbarMouseDownOffsetY: 0,
|
||||
keyboardVisible: false,
|
||||
|
||||
isTouchDevice: false,
|
||||
|
@ -198,13 +202,19 @@ var UI;
|
|||
document.getElementById("noVNC_control_bar")
|
||||
.addEventListener('keypress', UI.activateControlbar);
|
||||
|
||||
document.getElementById("noVNC_control_bar_handle")
|
||||
.addEventListener('click', UI.toggleControlbar);
|
||||
|
||||
document.getElementById("noVNC_view_drag_button")
|
||||
.addEventListener('click', UI.toggleViewDrag);
|
||||
document.getElementById("noVNC_send_ctrl_alt_del_button")
|
||||
.addEventListener('click', UI.sendCtrlAltDel);
|
||||
|
||||
document.getElementById("noVNC_control_bar_handle")
|
||||
.addEventListener('mousedown', UI.controlbarHandleMouseDown);
|
||||
document.getElementById("noVNC_control_bar_handle")
|
||||
.addEventListener('mouseup', UI.controlbarHandleMouseUp);
|
||||
document.getElementById("noVNC_control_bar_handle")
|
||||
.addEventListener('mousemove', UI.dragControlbarHandle);
|
||||
// resize events aren't available for elements
|
||||
window.addEventListener('resize', UI.updateControlbarHandle);
|
||||
},
|
||||
|
||||
addTouchSpecificHandlers: function() {
|
||||
|
@ -235,6 +245,13 @@ var UI;
|
|||
document.getElementById("noVNC_control_bar")
|
||||
.addEventListener('input', UI.activateControlbar);
|
||||
|
||||
document.getElementById("noVNC_control_bar_handle")
|
||||
.addEventListener('touchstart', UI.controlbarHandleMouseDown);
|
||||
document.getElementById("noVNC_control_bar_handle")
|
||||
.addEventListener('touchend', UI.controlbarHandleMouseUp);
|
||||
document.getElementById("noVNC_control_bar_handle")
|
||||
.addEventListener('touchmove', UI.dragControlbarHandle);
|
||||
|
||||
window.addEventListener('load', UI.keyboardinputReset);
|
||||
},
|
||||
|
||||
|
@ -497,6 +514,96 @@ var UI;
|
|||
}
|
||||
},
|
||||
|
||||
dragControlbarHandle: function (e) {
|
||||
if (!UI.controlbarGrabbed) return;
|
||||
|
||||
var ptr = Util.getPointerEvent(e);
|
||||
|
||||
if (!UI.controlbarDrag) {
|
||||
// The goal is to trigger on a certain physical width, the
|
||||
// devicePixelRatio brings us a bit closer but is not optimal.
|
||||
var dragThreshold = 10 * (window.devicePixelRatio || 1);
|
||||
var dragDistance = Math.abs(ptr.clientY - UI.controlbarMouseDownClientY);
|
||||
|
||||
if (dragDistance < dragThreshold) return;
|
||||
|
||||
UI.controlbarDrag = true;
|
||||
}
|
||||
|
||||
var eventY = ptr.clientY - UI.controlbarMouseDownOffsetY;
|
||||
|
||||
UI.moveControlbarHandle(eventY);
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
// Move the handle but don't allow any position outside the bounds
|
||||
moveControlbarHandle: function (posY) {
|
||||
var handle = document.getElementById("noVNC_control_bar_handle");
|
||||
var handleHeight = Util.getPosition(handle).height;
|
||||
var controlbar = document.getElementById("noVNC_control_bar");
|
||||
var controlbarBounds = Util.getPosition(controlbar);
|
||||
var controlbarTop = controlbarBounds.y;
|
||||
var controlbarBottom = controlbarBounds.y + controlbarBounds.height;
|
||||
var margin = 10;
|
||||
|
||||
var viewportY = posY;
|
||||
|
||||
// Refuse coordinates outside the control bar
|
||||
if (viewportY < controlbarTop + margin) {
|
||||
viewportY = controlbarTop + margin;
|
||||
} else if (viewportY > controlbarBottom - handleHeight - margin) {
|
||||
viewportY = controlbarBottom - handleHeight - margin;
|
||||
}
|
||||
|
||||
// Corner case: control bar too small for stable position
|
||||
if (controlbarBounds.height < (handleHeight + margin * 2)) {
|
||||
viewportY = controlbarTop + (controlbarBounds.height - handleHeight) / 2;
|
||||
}
|
||||
|
||||
var relativeY = viewportY - controlbarTop;
|
||||
handle.style.transform = "translateY(" + relativeY + "px)";
|
||||
},
|
||||
|
||||
updateControlbarHandle: function () {
|
||||
var handle = document.getElementById("noVNC_control_bar_handle");
|
||||
var pos = Util.getPosition(handle);
|
||||
UI.moveControlbarHandle(pos.y);
|
||||
},
|
||||
|
||||
controlbarHandleMouseUp: function(e) {
|
||||
if ((e.type == "mouseup") && (e.button != 0))
|
||||
return;
|
||||
|
||||
// mouseup and mousedown on the same place toggles the controlbar
|
||||
if (UI.controlbarGrabbed && !UI.controlbarDrag) {
|
||||
UI.toggleControlbar();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
UI.controlbarGrabbed = false;
|
||||
},
|
||||
|
||||
controlbarHandleMouseDown: function(e) {
|
||||
if ((e.type == "mousedown") && (e.button != 0))
|
||||
return;
|
||||
|
||||
var ptr = Util.getPointerEvent(e);
|
||||
|
||||
var handle = document.getElementById("noVNC_control_bar_handle");
|
||||
var bounds = handle.getBoundingClientRect();
|
||||
|
||||
WebUtil.setCapture(handle);
|
||||
UI.controlbarGrabbed = true;
|
||||
UI.controlbarDrag = false;
|
||||
|
||||
UI.controlbarMouseDownClientY = ptr.clientY;
|
||||
UI.controlbarMouseDownOffsetY = ptr.clientY - bounds.top;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
/* ------^-------
|
||||
* /VISUAL
|
||||
* ==============
|
||||
|
|
|
@ -278,6 +278,99 @@ WebUtil.injectParamIfMissing = function (path, param, value) {
|
|||
}
|
||||
};
|
||||
|
||||
// Emulate Element.setCapture() when not supported
|
||||
|
||||
WebUtil._captureRecursion = false;
|
||||
WebUtil._captureProxy = function (e) {
|
||||
// Recursion protection as we'll see our own event
|
||||
if (WebUtil._captureRecursion) return;
|
||||
|
||||
// Clone the event as we cannot dispatch an already dispatched event
|
||||
var newEv = new e.constructor(e.type, e);
|
||||
|
||||
WebUtil._captureRecursion = true;
|
||||
WebUtil._captureElem.dispatchEvent(newEv);
|
||||
WebUtil._captureRecursion = false;
|
||||
|
||||
// Implicitly release the capture on button release
|
||||
if ((e.type === "mouseup") || (e.type === "touchend")) {
|
||||
WebUtil.releaseCapture();
|
||||
}
|
||||
};
|
||||
|
||||
WebUtil.setCapture = function (elem) {
|
||||
if (elem.setCapture) {
|
||||
|
||||
elem.setCapture();
|
||||
|
||||
// IE releases capture on 'click' events which might not trigger
|
||||
elem.addEventListener('mouseup', WebUtil.releaseCapture);
|
||||
elem.addEventListener('touchend', WebUtil.releaseCapture);
|
||||
|
||||
} else {
|
||||
// Safari on iOS 9 has a broken constructor for TouchEvent.
|
||||
// We are fine in this case however, since Safari seems to
|
||||
// have some sort of implicit setCapture magic anyway.
|
||||
if (window.TouchEvent !== undefined) {
|
||||
try {
|
||||
new TouchEvent("touchstart");
|
||||
} catch (TypeError) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||
|
||||
if (captureElem === null) {
|
||||
captureElem = document.createElement("div");
|
||||
captureElem.id = "noVNC_mouse_capture_elem";
|
||||
captureElem.style.position = "fixed";
|
||||
captureElem.style.top = "0px";
|
||||
captureElem.style.left = "0px";
|
||||
captureElem.style.width = "100%";
|
||||
captureElem.style.height = "100%";
|
||||
captureElem.style.zIndex = 10000;
|
||||
captureElem.style.display = "none";
|
||||
document.body.appendChild(captureElem);
|
||||
|
||||
captureElem.addEventListener('mousemove', WebUtil._captureProxy);
|
||||
captureElem.addEventListener('mouseup', WebUtil._captureProxy);
|
||||
|
||||
captureElem.addEventListener('touchmove', WebUtil._captureProxy);
|
||||
captureElem.addEventListener('touchend', WebUtil._captureProxy);
|
||||
}
|
||||
|
||||
WebUtil._captureElem = elem;
|
||||
captureElem.style.display = null;
|
||||
|
||||
// We listen to events on window in order to keep tracking if it
|
||||
// happens to leave the viewport
|
||||
window.addEventListener('mousemove', WebUtil._captureProxy);
|
||||
window.addEventListener('mouseup', WebUtil._captureProxy);
|
||||
|
||||
window.addEventListener('touchmove', WebUtil._captureProxy);
|
||||
window.addEventListener('touchend', WebUtil._captureProxy);
|
||||
}
|
||||
};
|
||||
|
||||
WebUtil.releaseCapture = function () {
|
||||
if (document.releaseCapture) {
|
||||
|
||||
document.releaseCapture();
|
||||
|
||||
} else {
|
||||
var captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||
WebUtil._captureElem = null;
|
||||
captureElem.style.display = "none";
|
||||
|
||||
window.removeEventListener('mousemove', WebUtil._captureProxy);
|
||||
window.removeEventListener('mouseup', WebUtil._captureProxy);
|
||||
|
||||
window.removeEventListener('touchmove', WebUtil._captureProxy);
|
||||
window.removeEventListener('touchend', WebUtil._captureProxy);
|
||||
}
|
||||
};
|
||||
|
||||
// Dynamically load scripts without using document.write()
|
||||
// Reference: http://unixpapa.com/js/dyna.html
|
||||
//
|
||||
|
|
10
core/util.js
10
core/util.js
|
@ -204,14 +204,18 @@ Util.getPosition = function(obj) {
|
|||
'width': objPosition.width, 'height': objPosition.height};
|
||||
};
|
||||
|
||||
Util.getPointerEvent = function (e) {
|
||||
var evt;
|
||||
evt = (e ? e : window.event);
|
||||
evt = (evt.changedTouches ? evt.changedTouches[0] : evt.touches ? evt.touches[0] : evt);
|
||||
return evt;
|
||||
};
|
||||
|
||||
// Get mouse event position in DOM element
|
||||
Util.getEventPosition = function (e, obj, scale) {
|
||||
"use strict";
|
||||
var evt, docX, docY, pos;
|
||||
//if (!e) evt = window.event;
|
||||
evt = (e ? e : window.event);
|
||||
evt = (evt.changedTouches ? evt.changedTouches[0] : evt.touches ? evt.touches[0] : evt);
|
||||
evt = Util.getPointerEvent(e);
|
||||
if (evt.pageX || evt.pageY) {
|
||||
docX = evt.pageX;
|
||||
docY = evt.pageY;
|
||||
|
|
Loading…
Reference in New Issue