Remove old menu and UI, link clipboards between connections.

This commit is contained in:
Michael Jumper
2012-11-04 15:58:59 -08:00
parent 68b53e0c08
commit bf7a973477
10 changed files with 54 additions and 469 deletions

View File

@@ -25,61 +25,23 @@
<link rel="icon" type="image/png" href="images/guacamole-logo-64.png"/>
<link rel="stylesheet" type="text/css" href="styles/client.css"/>
<link rel="stylesheet" type="text/css" href="styles/keyboard.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=medium-dpi"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<title>Guacamole ${project.version}</title>
</head>
<body>
<!-- Menu -->
<div id="menu">
<!-- Clipboard -->
<button id="showClipboard">Show Clipboard</button>
<div id="clipboardDiv">
<h2>Clipboard</h2>
<p>
Text copied/cut within Guacamole will appear here. Changes to the text will affect the remote clipboard, and will be pastable within the remote desktop. Use the textbox below as an interface between the client and server clipboards.
</p>
<textarea rows="10" cols="40" id="clipboard"></textarea>
</div>
<button id="showKeyboard">Show Keyboard</button>
<button id="ctrlAltDelete">Ctrl-Alt-Delete</button>
<button id="logout">Logout</button>
<!-- Logo and status -->
<img id="status-logo" class="logo" src="images/guacamole-logo-24.png" alt="Guacamole" title="Guacamole ${project.version}"/>
</div>
<!-- Touch-specific menu -->
<div id="touchMenu"><img id="touchShowClipboard" src="images/menu-icons/tango/edit-paste.png"/><img id="touchShowKeyboard" src="images/menu-icons/tango/input-keyboard.png"/><img id="touchLogout" src="images/menu-icons/tango/system-log-out.png"/></div>
<!-- Touch-specific clipboard -->
<div id="touchClipboardDiv">
<h2>Clipboard</h2>
<p>
Text copied/cut within Guacamole will appear here. Changes to the text will affect the remote clipboard, and will be pastable within the remote desktop. Use the textbox below as an interface between the client and server clipboards.
</p>
<textarea rows="10" cols="40" id="touchClipboard"></textarea>
</div>
<!-- Keyboard event target for platforms with native OSKs -->
<textarea id="eventTarget"></textarea>
<!-- Display -->
<div id="display">
<!-- Menu trigger -->
<div id="menuControl"></div>
</div>
<!-- On-screen keyboard -->
<div id="keyboardContainer"></div>
<!-- Dimensional clone of viewport -->
<div id="viewportClone"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -81,6 +81,14 @@
<div id="other-connections">
</div>
<h2>Clipboard</h2>
<div id="clipboardDiv">
<p>
Text copied/cut within Guacamole will appear here. Changes to the text will affect the remote clipboard, and will be pastable within the remote desktop. Use the textbox below as an interface between the client and server clipboards.
</p>
<textarea rows="10" cols="40" id="clipboard"></textarea>
</div>
</div>
<div id="version-dialog">
@@ -92,6 +100,29 @@
<!-- Init -->
<script type="text/javascript"> /* <![CDATA[ */
var clients = [];
var clipboard = document.getElementById("clipboard");
clipboard.onchange = function() {
propagateClipboard(clipboard.value);
};
function setClipboard(text) {
clipboard.value = text;
propagateClipboard(text);
}
// Propogate clipboard data across all open clients
function propagateClipboard(text) {
for (var i=0; i<clients.length; i++) {
var guac = clients[i].GuacamoleUI.client;
if (guac)
guac.setClipboard(text);
}
}
// Constructs the URL for a client which connects to the connection
// with the given id.
function getClientURL(id) {
@@ -125,12 +156,6 @@
}
// If only one connection, redirect to that.
if (configs.length == 1) {
window.location.href = getClientURL(configs[0].id);
return;
}
// Remove all rows from connections list
var recent_connections = document.getElementById("recent-connections");
var other_connections = document.getElementById("other-connections");
@@ -171,9 +196,9 @@
var thumbnail = document.createElement("div");
thumbnail.className = "thumbnail";
function redirect(url) {
function new_client(url) {
return function() {
window.location = url;
clients.push(window.open(url));
};
}
@@ -181,7 +206,7 @@
var clientLink = document.createElement("a");
var url = getClientURL(configs[i].id)
clientLink.setAttribute("href", url);
connection.onclick = redirect(url);
connection.onclick = new_client(url);
protocol.appendChild(protocolIcon);

View File

@@ -2,62 +2,23 @@
// UI Definition
var GuacamoleUI = {
"LOGOUT_PROMPT" : "Logging out will disconnect all of your active "
+ "Guacamole sessions. Are you sure you wish to log out?",
/* Detection Constants */
"LONG_PRESS_DETECT_TIMEOUT" : 800, /* milliseconds */
"LONG_PRESS_MOVEMENT_THRESHOLD" : 10, /* pixels */
"MENU_CLOSE_DETECT_TIMEOUT" : 500, /* milliseconds */
"MENU_OPEN_DETECT_TIMEOUT" : 325, /* milliseconds */
"KEYBOARD_AUTO_RESIZE_INTERVAL" : 30, /* milliseconds */
/* Animation Constants */
"MENU_SHADE_STEPS" : 10, /* frames */
"MENU_SHADE_INTERVAL" : 30, /* milliseconds */
"MENU_SHOW_STEPS" : 5, /* frames */
"MENU_SHOW_INTERVAL" : 30, /* milliseconds */
/* OSK Mode Constants */
"OSK_MODE_NATIVE" : 1, /* "Show Keyboard" will show the platform's native OSK */
"OSK_MODE_GUAC" : 2, /* "Show Keyboard" will show Guac's built-in OSK */
/* UI Elements */
"viewport" : document.getElementById("viewportClone"),
"display" : document.getElementById("display"),
"menu" : document.getElementById("menu"),
"menuControl" : document.getElementById("menuControl"),
"touchMenu" : document.getElementById("touchMenu"),
"logo" : document.getElementById("status-logo"),
"eventTarget" : document.getElementById("eventTarget"),
"buttons": {
"showClipboard": document.getElementById("showClipboard"),
"showKeyboard" : document.getElementById("showKeyboard"),
"ctrlAltDelete": document.getElementById("ctrlAltDelete"),
"reconnect" : document.getElementById("reconnect"),
"logout" : document.getElementById("logout"),
"touchShowClipboard" : document.getElementById("touchShowClipboard"),
"touchShowKeyboard" : document.getElementById("touchShowKeyboard"),
"touchLogout" : document.getElementById("touchLogout")
"reconnect" : document.getElementById("reconnect")
},
"containers": {
"state" : document.getElementById("statusDialog"),
"clipboard" : document.getElementById("clipboardDiv"),
"touchClipboard": document.getElementById("touchClipboardDiv"),
"keyboard" : document.getElementById("keyboardContainer")
"state" : document.getElementById("statusDialog")
},
"state" : document.getElementById("statusText"),
"clipboard" : document.getElementById("clipboard"),
"touchClipboard" : document.getElementById("touchClipboard")
"client" : null
};
@@ -76,11 +37,6 @@ GuacamoleUI.supportedVideo = [];
// Constant UI initialization and behavior
(function() {
var menu_shaded = false;
var shade_interval = null;
var show_interval = null;
// Cache error image (might not be available when error occurs)
var guacErrorImage = new Image();
guacErrorImage.src = "images/noguacamole-logo-24.png";
@@ -154,10 +110,6 @@ GuacamoleUI.supportedVideo = [];
GuacamoleUI.display.style.opacity = "0.1";
};
GuacamoleUI.hideTouchMenu = function() {
GuacamoleUI.touchMenu.style.display = "none";
};
function positionCentered(element) {
element.style.left =
((GuacamoleUI.viewport.offsetWidth - element.offsetWidth) / 2
@@ -170,322 +122,11 @@ GuacamoleUI.supportedVideo = [];
+ "px";
}
GuacamoleUI.showTouchMenu = function() {
GuacamoleUI.touchMenu.style.display= "";
positionCentered(GuacamoleUI.touchMenu);
};
GuacamoleUI.hideTouchClipboard = function() {
GuacamoleUI.touchClipboard.blur();
GuacamoleUI.containers.touchClipboard.style.visibility = "hidden";
};
GuacamoleUI.showTouchClipboard = function() {
positionCentered(GuacamoleUI.containers.touchClipboard);
GuacamoleUI.containers.touchClipboard.style.visibility = "visible";
};
GuacamoleUI.shadeMenu = function() {
if (!menu_shaded) {
var step = Math.floor(GuacamoleUI.menu.offsetHeight / GuacamoleUI.MENU_SHADE_STEPS) + 1;
var offset = 0;
menu_shaded = true;
window.clearInterval(show_interval);
shade_interval = window.setInterval(function() {
offset -= step;
GuacamoleUI.menu.style.transform =
GuacamoleUI.menu.style.WebkitTransform =
GuacamoleUI.menu.style.MozTransform =
GuacamoleUI.menu.style.OTransform =
GuacamoleUI.menu.style.msTransform =
"translateY(" + offset + "px)";
if (offset <= -GuacamoleUI.menu.offsetHeight) {
window.clearInterval(shade_interval);
GuacamoleUI.menu.style.visiblity = "hidden";
}
}, GuacamoleUI.MENU_SHADE_INTERVAL);
}
};
GuacamoleUI.showMenu = function() {
if (menu_shaded) {
var step = Math.floor(GuacamoleUI.menu.offsetHeight / GuacamoleUI.MENU_SHOW_STEPS) + 1;
var offset = -GuacamoleUI.menu.offsetHeight;
menu_shaded = false;
GuacamoleUI.menu.style.visiblity = "";
window.clearInterval(shade_interval);
show_interval = window.setInterval(function() {
offset += step;
if (offset >= 0) {
offset = 0;
window.clearInterval(show_interval);
}
GuacamoleUI.menu.style.transform =
GuacamoleUI.menu.style.WebkitTransform =
GuacamoleUI.menu.style.MozTransform =
GuacamoleUI.menu.style.OTransform =
GuacamoleUI.menu.style.msTransform =
"translateY(" + offset + "px)";
}, GuacamoleUI.MENU_SHOW_INTERVAL);
}
};
// Show/Hide clipboard
GuacamoleUI.buttons.showClipboard.onclick = function() {
var displayed = GuacamoleUI.containers.clipboard.style.display;
if (displayed != "block") {
GuacamoleUI.containers.clipboard.style.display = "block";
GuacamoleUI.buttons.showClipboard.innerHTML = "Hide Clipboard";
}
else {
GuacamoleUI.containers.clipboard.style.display = "none";
GuacamoleUI.buttons.showClipboard.innerHTML = "Show Clipboard";
GuacamoleUI.clipboard.onchange();
}
};
GuacamoleUI.buttons.touchShowClipboard.onclick = function() {
GuacamoleUI.hideTouchMenu();
GuacamoleUI.showTouchClipboard();
};
// Show/Hide keyboard
var keyboardResizeInterval = null;
GuacamoleUI.buttons.showKeyboard.onclick = function() {
// If Guac OSK shown, hide it.
var displayed = GuacamoleUI.containers.keyboard.style.display;
if (displayed == "block") {
GuacamoleUI.containers.keyboard.style.display = "none";
GuacamoleUI.buttons.showKeyboard.textContent = "Show Keyboard";
window.onresize = null;
window.clearInterval(keyboardResizeInterval);
}
// Otherwise, show it
else {
// Ensure event target is NOT focused if we are using the Guac OSK.
GuacamoleUI.eventTarget.blur();
GuacamoleUI.containers.keyboard.style.display = "block";
GuacamoleUI.buttons.showKeyboard.textContent = "Hide Keyboard";
// Automatically update size
window.onresize = updateKeyboardSize;
keyboardResizeInterval = window.setInterval(updateKeyboardSize,
GuacamoleUI.KEYBOARD_AUTO_RESIZE_INTERVAL);
updateKeyboardSize();
}
};
// Touch-specific keyboard show
GuacamoleUI.buttons.touchShowKeyboard.onclick =
function(e) {
// Center event target in case browser automatically centers
// input fields on focus.
GuacamoleUI.eventTarget.style.left =
(window.pageXOffset + GuacamoleUI.viewport.offsetWidth / 2) + "px";
GuacamoleUI.eventTarget.style.top =
(window.pageYOffset + GuacamoleUI.viewport.offsetHeight / 2) + "px";
GuacamoleUI.eventTarget.focus();
GuacamoleUI.hideTouchMenu();
};
// Logout
GuacamoleUI.buttons.logout.onclick =
GuacamoleUI.buttons.touchLogout.onclick =
function() {
// Logout after warning user about session disconnect
if (confirm(GuacamoleUI.LOGOUT_PROMPT)) {
window.location.href = "logout";
GuacamoleUI.hideTouchMenu();
}
};
// Timeouts for detecting if users wants menu to open or close
var detectMenuOpenTimeout = null;
var detectMenuCloseTimeout = null;
// Clear detection timeouts
GuacamoleUI.resetMenuDetect = function() {
if (detectMenuOpenTimeout != null) {
window.clearTimeout(detectMenuOpenTimeout);
detectMenuOpenTimeout = null;
}
if (detectMenuCloseTimeout != null) {
window.clearTimeout(detectMenuCloseTimeout);
detectMenuCloseTimeout = null;
}
};
// Initiate detection of menu open action. If not canceled through some
// user event, menu will open.
GuacamoleUI.startMenuOpenDetect = function() {
if (!detectMenuOpenTimeout) {
// Clear detection state
GuacamoleUI.resetMenuDetect();
// Wait and then show menu
detectMenuOpenTimeout = window.setTimeout(function() {
// If menu opened via mouse, do not show native OSK
GuacamoleUI.oskMode = GuacamoleUI.OSK_MODE_GUAC;
GuacamoleUI.showMenu();
detectMenuOpenTimeout = null;
}, GuacamoleUI.MENU_OPEN_DETECT_TIMEOUT);
}
};
// Initiate detection of menu close action. If not canceled through some
// user mouse event, menu will close.
GuacamoleUI.startMenuCloseDetect = function() {
if (!detectMenuCloseTimeout) {
// Clear detection state
GuacamoleUI.resetMenuDetect();
// Wait and then shade menu
detectMenuCloseTimeout = window.setTimeout(function() {
GuacamoleUI.shadeMenu();
detectMenuCloseTimeout = null;
}, GuacamoleUI.MENU_CLOSE_DETECT_TIMEOUT);
}
};
// Show menu if mouseover any part of menu
GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.showMenu, true);
// Stop detecting menu state change intents if mouse is over menu
GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.resetMenuDetect, true);
// When mouse hovers over top of screen, start detection of intent to open menu
GuacamoleUI.menuControl.addEventListener('mousemove', GuacamoleUI.startMenuOpenDetect, true);
var long_press_start_x = 0;
var long_press_start_y = 0;
var menuShowLongPressTimeout = null;
GuacamoleUI.startLongPressDetect = function() {
if (!menuShowLongPressTimeout) {
menuShowLongPressTimeout = window.setTimeout(function() {
menuShowLongPressTimeout = null;
// Assume native OSK if menu shown via long-press
GuacamoleUI.oskMode = GuacamoleUI.OSK_MODE_NATIVE;
GuacamoleUI.showTouchMenu();
}, GuacamoleUI.LONG_PRESS_DETECT_TIMEOUT);
}
};
GuacamoleUI.stopLongPressDetect = function() {
window.clearTimeout(menuShowLongPressTimeout);
menuShowLongPressTimeout = null;
};
// Detect long-press at bottom of screen
GuacamoleUI.display.addEventListener('touchstart', function(e) {
// Close menu if shown
GuacamoleUI.shadeMenu();
GuacamoleUI.hideTouchMenu();
GuacamoleUI.hideTouchClipboard();
// Record touch location
if (e.touches.length == 1) {
var touch = e.touches[0];
long_press_start_x = touch.screenX;
long_press_start_y = touch.screenY;
}
// Start detection
GuacamoleUI.startLongPressDetect();
}, true);
// Stop detection if touch moves significantly
GuacamoleUI.display.addEventListener('touchmove', function(e) {
// If touch distance from start exceeds threshold, cancel long press
var touch = e.touches[0];
if (Math.abs(touch.screenX - long_press_start_x) >= GuacamoleUI.LONG_PRESS_MOVEMENT_THRESHOLD
|| Math.abs(touch.screenY - long_press_start_y) >= GuacamoleUI.LONG_PRESS_MOVEMENT_THRESHOLD)
GuacamoleUI.stopLongPressDetect();
}, true);
// Stop detection if press stops
GuacamoleUI.display.addEventListener('touchend', GuacamoleUI.stopLongPressDetect, true);
// Close menu on mouse movement
GuacamoleUI.display.addEventListener('mousemove', GuacamoleUI.startMenuCloseDetect, true);
GuacamoleUI.display.addEventListener('mousedown', GuacamoleUI.startMenuCloseDetect, true);
// Reconnect button
GuacamoleUI.buttons.reconnect.onclick = function() {
window.location.reload();
};
// On-screen keyboard
GuacamoleUI.keyboard = new Guacamole.OnScreenKeyboard("layouts/en-us-qwerty.xml");
GuacamoleUI.containers.keyboard.appendChild(GuacamoleUI.keyboard.getElement());
// Function for automatically updating keyboard size
var lastKeyboardWidth;
function updateKeyboardSize() {
var currentSize = GuacamoleUI.keyboard.getElement().offsetWidth;
if (lastKeyboardWidth != currentSize) {
GuacamoleUI.keyboard.resize(currentSize);
lastKeyboardWidth = currentSize;
}
};
// Turn off autocorrect and autocapitalization on eventTarget
GuacamoleUI.eventTarget.setAttribute("autocorrect", "off");
GuacamoleUI.eventTarget.setAttribute("autocapitalize", "off");
@@ -567,6 +208,8 @@ GuacamoleUI.supportedVideo = [];
// Tie UI events / behavior to a specific Guacamole client
GuacamoleUI.attach = function(guac) {
GuacamoleUI.client = guac;
var title_prefix = null;
var connection_name = "Guacamole";
@@ -592,9 +235,6 @@ GuacamoleUI.attach = function(guac) {
}
// When mouse enters display, start detection of intent to close menu
guac_display.addEventListener('mouseover', GuacamoleUI.startMenuCloseDetect, true);
guac_display.onclick = function(e) {
e.preventDefault();
return false;
@@ -804,7 +444,6 @@ GuacamoleUI.attach = function(guac) {
// Connecting
case 1:
GuacamoleUI.shadeMenu();
GuacamoleUI.showStatus("Connecting...");
title_prefix = "[Connecting...]";
break;
@@ -891,62 +530,9 @@ GuacamoleUI.attach = function(guac) {
};
// Handle clipboard events
GuacamoleUI.clipboard.onchange = function() {
var text = GuacamoleUI.clipboard.value;
GuacamoleUI.touchClipboard.value = text;
guac.setClipboard(text);
};
GuacamoleUI.touchClipboard.onchange = function() {
var text = GuacamoleUI.touchClipboard.value;
GuacamoleUI.clipboard.value = text;
guac.setClipboard(text);
};
// Ignore keypresses when clipboard is focused
GuacamoleUI.clipboard.onfocus =
GuacamoleUI.touchClipboard.onfocus = function() {
disableKeyboard();
};
// Capture keypresses when clipboard is not focused
GuacamoleUI.clipboard.onblur =
GuacamoleUI.touchClipboard.onblur = function() {
enableKeyboard();
};
// Server copy handler
guac.onclipboard = function(data) {
GuacamoleUI.clipboard.value = data;
GuacamoleUI.touchClipboard.value = data;
};
GuacamoleUI.keyboard.onkeydown = function(keysym) {
guac.sendKeyEvent(1, keysym);
};
GuacamoleUI.keyboard.onkeyup = function(keysym) {
guac.sendKeyEvent(0, keysym);
};
// Send Ctrl-Alt-Delete
GuacamoleUI.buttons.ctrlAltDelete.onclick = function() {
var KEYSYM_CTRL = 0xFFE3;
var KEYSYM_ALT = 0xFFE9;
var KEYSYM_DELETE = 0xFFFF;
guac.sendKeyEvent(1, KEYSYM_CTRL);
guac.sendKeyEvent(1, KEYSYM_ALT);
guac.sendKeyEvent(1, KEYSYM_DELETE);
guac.sendKeyEvent(0, KEYSYM_DELETE);
guac.sendKeyEvent(0, KEYSYM_ALT);
guac.sendKeyEvent(0, KEYSYM_CTRL);
window.opener.setClipboard(data);
};
};

View File

@@ -146,7 +146,11 @@ div.dialog p {
top: 0;
width: 100%;
z-index: 4;
background: #FEA;
background: #888;
padding: 0.5em;
font-weight: bold;
text-shadow: -1px -1px rgba(0, 0, 0, 0.6);
color: rgba(255, 255, 255, 0.7);
border-bottom: 1px solid black;
font-size: 0.8em;
}

View File

@@ -360,3 +360,11 @@ div#recent-connections .protocol {
.caption .name {
margin-left: 0.25em;
}
#clipboardDiv {
padding: 1em;
}
#clipboardDiv textarea {
width: 100%;
}