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 {
|
#noVNC_control_bar_handle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -15px;
|
right: -15px;
|
||||||
top: 10%;
|
top: 0;
|
||||||
|
transform: translateY(35px);
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
z-index: -2;
|
z-index: -2;
|
||||||
|
|
113
app/ui.js
113
app/ui.js
|
@ -43,6 +43,10 @@ var UI;
|
||||||
hideKeyboardTimeout: null,
|
hideKeyboardTimeout: null,
|
||||||
controlbarTimeout: null,
|
controlbarTimeout: null,
|
||||||
|
|
||||||
|
controlbarGrabbed: false,
|
||||||
|
controlbarDrag: false,
|
||||||
|
controlbarMouseDownClientY: 0,
|
||||||
|
controlbarMouseDownOffsetY: 0,
|
||||||
keyboardVisible: false,
|
keyboardVisible: false,
|
||||||
|
|
||||||
isTouchDevice: false,
|
isTouchDevice: false,
|
||||||
|
@ -198,13 +202,19 @@ var UI;
|
||||||
document.getElementById("noVNC_control_bar")
|
document.getElementById("noVNC_control_bar")
|
||||||
.addEventListener('keypress', UI.activateControlbar);
|
.addEventListener('keypress', UI.activateControlbar);
|
||||||
|
|
||||||
document.getElementById("noVNC_control_bar_handle")
|
|
||||||
.addEventListener('click', UI.toggleControlbar);
|
|
||||||
|
|
||||||
document.getElementById("noVNC_view_drag_button")
|
document.getElementById("noVNC_view_drag_button")
|
||||||
.addEventListener('click', UI.toggleViewDrag);
|
.addEventListener('click', UI.toggleViewDrag);
|
||||||
document.getElementById("noVNC_send_ctrl_alt_del_button")
|
document.getElementById("noVNC_send_ctrl_alt_del_button")
|
||||||
.addEventListener('click', UI.sendCtrlAltDel);
|
.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() {
|
addTouchSpecificHandlers: function() {
|
||||||
|
@ -235,6 +245,13 @@ var UI;
|
||||||
document.getElementById("noVNC_control_bar")
|
document.getElementById("noVNC_control_bar")
|
||||||
.addEventListener('input', UI.activateControlbar);
|
.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);
|
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
|
* /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()
|
// Dynamically load scripts without using document.write()
|
||||||
// Reference: http://unixpapa.com/js/dyna.html
|
// 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};
|
'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
|
// Get mouse event position in DOM element
|
||||||
Util.getEventPosition = function (e, obj, scale) {
|
Util.getEventPosition = function (e, obj, scale) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var evt, docX, docY, pos;
|
var evt, docX, docY, pos;
|
||||||
//if (!e) evt = window.event;
|
evt = Util.getPointerEvent(e);
|
||||||
evt = (e ? e : window.event);
|
|
||||||
evt = (evt.changedTouches ? evt.changedTouches[0] : evt.touches ? evt.touches[0] : evt);
|
|
||||||
if (evt.pageX || evt.pageY) {
|
if (evt.pageX || evt.pageY) {
|
||||||
docX = evt.pageX;
|
docX = evt.pageX;
|
||||||
docY = evt.pageY;
|
docY = evt.pageY;
|
||||||
|
|
Loading…
Reference in New Issue