0

Fix up remoting UI to make it closer to spec

BUG=NONE
TEST=Run Remoting and appreciate it's new shininess.

Review URL: http://codereview.chromium.org/7078022

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@87692 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
dmaclach@chromium.org
2011-06-02 21:36:03 +00:00
parent e3037f5d75
commit f2d714796a
12 changed files with 607 additions and 537 deletions

@ -5,5 +5,5 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<html>
<script type="text/javascript" src="background.js"></script>
<script src="background.js"></script>
</html>

@ -0,0 +1,186 @@
/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Elements */
a {
color: rgb(0, 102, 204);
text-decoration: none;
}
body {
background: -webkit-gradient(radial, center center, 0, center center, 400,
from(rgb(254, 254, 254)),
to(rgb(239, 239, 239)));
font-family: Arial, sans-serif;
margin:0;
padding:0;
}
button {
background: -webkit-linear-gradient(#fafafa, #f4f4f4 40%, #e5e5e5);
border: 1px solid #aaa;
height: 2em;
font-size: 16px;
padding: .5em 1em;
-webkit-border-radius: 2px;
-webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
-webkit-user-select: none;
}
button:hover {
background: #ebebeb -webkit-linear-gradient(#fefefe, #f8f8f8 40%, #e9e9e9);
border-color: #999;
color: #222;
-webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.2);
}
button:active {
background: #ebebeb -webkit-linear-gradient(#f4f4f4, #efefef 40%, #dcdcdc);
color: #333;
-webkit-box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.2);
}
button[disabled], .button[disabled]:hover {
background: -webkit-linear-gradient(#fafafa, #f4f4f4 40%, #e5e5e5);
border-color: #aaa;
color: #888;
-webkit-box-shadow: none;
}
footer {
font-size: 14px;
text-align: center;
}
header h1 {
font-size: 24px;
font-weight: normal;
margin-left: 10px;
}
label {
color: black;
font-weight: bold;
}
section {
margin-top: 17px;
padding-bottom: 20px;
}
/* Classes */
.auth-status-control {
/* Class used to denote controls that affect authorization status. */
}
.centered-form {
/*
Used to force buttons to center correctly on Chrome due to bug laying out
buttons. http://crbug.com/84654
When 84654 is fixed we can remove the forms that have this class that
are wrapping our buttons.
*/
margin: 25px auto;
display: table;
}
.client-element {
/* Class used to denote client UI elements. */
}
.description {
margin-bottom: 25px;
}
.display-inline {
/*
Class used to denote elements that should be displayed inline as opposed
to block.
*/
}
.host-element {
/* Class used to denote host UI elements. */
}
.icon-label {
display: inline-block;
vertical-align: top;
}
.message {
text-align:center;
}
.mode {
/*
Class used to denote different modes of a given UI.
e.g. "Connecting" is a mode of the client UI.
*/
}
/* Ids */
#auth-panel {
border-bottom: 2px solid gray;
padding: 5px 10px;
}
#access-code-display {
background-color: lightgray;
border-style: solid;
font-size: 200%;
margin: 0 auto 25px auto;
padding: 0 4px 0 4px;
text-align: center;
width: 350px;
}
#access-code-entry {
font-weight: bold;
font-size: 18px;
height: 25px;
margin: 0 10px;
padding-left: 5px;
width: 12em;
}
#access-code-entry-row {
text-align: center;
}
#main-panel {
color: rgb(115, 115, 115);
font-size: 16px;
margin: 100px auto 0 auto;
padding: 10px;
width: 640px;
}
#current-email {
color: rgba(0, 0, 0, 0.5);
}
#divider-top {
margin: 10px 0 15px 0;
}
#divider-bottom {
margin: 25px 0 10px 0;
}
#icon {
height: 64px;
width: 64px;
}
#oauth2-entry {
display: inline-block;
width: 400px;
}
#server-response {
font-weight: bolder;
}

@ -6,188 +6,189 @@ found in the LICENSE file.
-->
<html>
<head>
<link rel="stylesheet" type="text/css" href="main.css" />
<script type="text/javascript" src="remoting.js"></script>
<script type="text/javascript" src="oauth2.js"></script>
<title>Select Role</title>
<meta charset="utf-8" />
<link rel="shortcut icon" href="chromoting128.png" />
<link rel="stylesheet" href="main.css" />
<link rel="stylesheet" href="choice.css" />
<script src="remoting.js"></script>
<script src="oauth2.js"></script>
<title>Chromoting</title>
</head>
<body onload="init();">
<!-- Auth panel -->
<div id="auth_panel">
OAuth2 Token: <span id="oauth2_status"></span>
<button onclick="remoting.oauth2.openOAuth2Window();"
id="oauth2_code_button">
Open OAuth2 Window
</button>
<button onclick="clearOAuth2();" id="oauth2_clear_button">
Clear
</button>
<form id='oauth2_form' action=""
onsubmit="authorizeOAuth2(this['oauth2_code'].value); return false;"
style="display:none">
<label for="auth2_code">OAuth2 Code (from window):</label>
<input type="text" name="oauth2_code" id="oauth2_code" />
<input type="submit"/>
</form>
<div id="email_div">
Current Email: <span id="current_email"></span>
<form id='new_email_form' action=""
onsubmit="setEmail(this); return false;">
<label for="new_email">New Email:</label>
<input type="text" name="new_email" id="new_email" />
<input type="submit" name="Set E-mail"/>
<body>
<div id="auth-panel">
<span id="oauth2-entry">
<form action="" onsubmit="authorizeOAuth2(); return false;">
<label for="oauth2-code">OAuth2 Token:</label>
<input id="oauth2-code" class="display-inline" type="text"
onkeyup="handleOAuth2CodeChange();"
onchange="handleOAuth2CodeChange();" />
<input id="oauth2-submit-button" class="display-inline"
type="submit" />
<input id="oauth2-code-button" class="display-inline" type="button"
onclick="remoting.oauth2.openOAuth2Window(); return false;"
value="Get OAuth2 Token&hellip;" />
<input id="oauth2-clear-button" class="display-inline" type="button"
onclick="clearOAuth2(); return false;" value="Revoke" />
</form>
</div>
<div id="xmpp_div" style="display:none;">
XMPP Token: <span id="xmpp_status"></span>
<button onclick="clearXmpp();" id="xmpp_clear" style="display:none;">
Clear
</button>
</span> <!-- oauth2-entry -->
<form id='xmpp_form' action=""
onsubmit="authorizeXmpp(this); return false;">
<label for="xmpp_username">Email:</label>
<input type="text" name="xmpp_username" id="xmpp_username" />
<label for="xmpp_password">App-specific Password:</label>
<input type="password" name="xmpp_password" id="xmpp_password" />
<div id="xmpp_captcha" style="display:none;">
<img style="display:block;" id="xmpp_captcha_img" />
<input type="hidden" name="xmpp_captcha_token" />
<input type="text" name="xmpp_captcha_result" />
<span id="email-entry">
<form action=""
onsubmit="setEmail(this['new-email'].value); return false;">
<label for="new-email">Email:</label>
<span id="current-email" class="display-inline"></span>
<input id="new-email" class="display-inline" name="new-email"
type="text" />
<input id="email-submit-button" class="display-inline"
type="submit" />
<input id="change-email-button" class="display-inline" type="button"
onclick="setEmail(''); return false;" value="Change Email" />
</form>
</span> <!-- email-entry -->
</div> <!-- auth-panel -->
<div id="main-panel">
<header>
<img id="icon" src="chromoting128.png">
<h1 class="icon-label host-element display-inline">
Chromoting&nbsp;>&nbsp;Share
</h1>
<h1 class="icon-label client-element display-inline">
Chromoting&nbsp;>&nbsp;Connect
</h1>
<img id="divider-top" src="dividertop.png">
</header>
<section id="host-section" class="host-element">
<div id="unshared" class="mode">
<div class="description">
With Chromoting you can easily let another Chrome user see and
control your computer.
</div>
<input type="submit"/>
</form>
<span id="xmpp_last_error" style="display:none"></span>
<iframe id="xmpp_error" style="display:none">
<p> No iframe support
</iframe>
</div>
<form class="centered-form">
<button id="share-button" class="auth-status-control"
type="button" onclick="tryShare(); return false;">
Share this computer
</button>
</form>
</div> <!-- unshared -->
<div id="preparing-to-share" class="mode">
<div class="message">
Connecting...
</div>
</div> <!-- preparing-to-share -->
<div id="ready-to-share" class="mode">
<div class="description">
To begin sharing your desktop, read out the access code below to the
person who will be assisting you.
</div>
<div id="access-code-display">
FAILED!
</div>
<div class="message">
Waiting for connection...
</div>
<form class="centered-form">
<button type="button" onclick="cancelShare(); return false;">
Cancel
</button>
</form>
</div> <!-- ready-to-share -->
<div id="shared" class="mode">
<div class="message">
Your desktop is currently being shared.
</div>
<form class="centered-form">
<button type="button" onclick="cancelShare(); return false;">
Stop sharing
</button>
</form>
</div> <!-- shared -->
</section> <!-- host-section -->
<section id="client-section" class="client-element">
<div id="unconnected" class="mode">
<div class="description">
Have the user whose computer you wish to access click
Share this computer with another user and then have them read
their access code to you.
</div>
<div id="access-code-entry-row">
<form action="">
<label class="auth-status-control" for="access-code-entry">
Access code:
</label>
<input id="access-code-entry" class="auth-status-control"
type="text"/>
</form>
<form class="centered-form">
<button id="connect-button" class="auth-status-control"
type="button" onclick="tryConnect(); return false;">
Connect
</button>
</form>
</div> <!-- code-entry-row -->
</div> <!-- unconnected -->
<div id="connecting" class="mode">
<div class="message">
Verifying access code...
<!-- TODO(jamiewalch): Implement Cancel, being careful when ignoring
the eventual server response not to ignore responses for any
subsequent requests.
<form class="centered-form">
<button onclick="cancelConnect(); return false;">
Cancel
</button>
</form>
-->
</div>
</div> <!-- connecting -->
<div id="connect-failed" class="mode">
<div id="invalid-access-code" class="message">
Invalid access code.
</div>
<div id="other-connect-error" class="message">
An error occurred. The server response was
<div id="server-response"></div>.
</div>
<form class="centered-form">
<button type="button"
onclick="setClientMode('unconnected'); return false;">
OK
</button>
</form>
</div> <!-- connect-failed -->
</section> <!-- client-section -->
<footer>
<img id="divider-bottom" src="dividerbottom.png">
<div class="client-element">
Click here to
<a class="switch-mode"
href="#"
onclick="setGlobalModePersistent(remoting.HOST_MODE);
return false;">
share this computer with another user</a>.
</div> <!-- client-footer -->
<div class="host-element">
Click here to <a class="switch-mode"
href="#"
onclick="setGlobalModePersistent(remoting.CLIENT_MODE);
return false;">
access a shared computer</a>.
</div> <!-- host-footer -->
</footer>
</div> <!-- main-panel -->
<div id="plugin-wrapper">
</div>
<!-- Host UI -->
<div id="host">
<div id="plugin_wrapper">
</div>
<div id="unshared">
<p class="message">
Your desktop is currently unshared.
</p>
<button type="button"
class="ok"
onclick="tryShare();">
Start sharing
</button>
<p>
<a class="switch_mode"
href="#c"
onclick="setGlobalModePersistent('client');">
I want to connect to another computer instead...
</a>
</p>
</div>
<div id="preparing_to_share">
<p class="message">
Connecting...
</p>
</div>
<div id="ready_to_share">
<p class="message">
To begin sharing your desktop, read out the access code below to the
person who will be assisting you.
</p>
<p id="access_code_display">
FAILED!
</p>
<p class="message">
Waiting for connection...
<button type="button"
class="cancel"
onclick="cancelShare();">
Cancel
</button>
</p>
<p class="message mock">
(For this mock-up, this message will disappear automatically.)
</p>
</div>
<div id="shared">
<p class="message">
Your desktop is currently being shared.
</p>
<button type="button"
class="cancel"
onclick="cancelShare();">
Stop sharing
</button>
</div>
</div>
<!-- Client UI -->
<div id="client">
<div id="unconnected">
<p class="message">
To connect to another computer, enter the access code provided to you
by that computer's user.
</p>
<form action="" onsubmit="tryConnect(this['access_code_entry'].value);
return false;">
<input type="text"
id="access_code_entry"/>
<button type="submit">
Connect
</button>
</form>
<a class="switch_mode"
href="#h"
onclick="setGlobalModePersistent('host');">
I want to share this computer instead...
</a>
</div>
<div id="connecting">
<p class="message">
Verifying access code...
<!-- TODO(jamiewalch): Implement Cancel, being careful when ignoring
the eventual server response not to ignore responses for any
subsequent requests.
<button type="button"
class="cancel"
onclick="cancelConnect();">
Cancel
</button>
-->
</p>
</div>
<div id="connect_failed">
<p class="message"
id="invalid_access_code">
Invalid access code.
</p>
<p class="message"
id="other_connect_error">
An error occurred. The server response was
<strong id="server_response"></strong>.
</p>
<button type="button"
class="ok"
onclick="setClientMode('unconnected');">
OK
</button>
</div>
</div>
</body>
</html>

Binary file not shown.

Before

(image error) Size: 7.6 KiB

After

(image error) Size: 6.6 KiB

Binary file not shown.

After

(image error) Size: 2.7 KiB

Binary file not shown.

After

(image error) Size: 4.5 KiB

@ -3,165 +3,6 @@
* found in the LICENSE file.
*/
body {
font-family: Helvetica, sans-serif;
cursor: default;
font-size: 13px;
}
p {
color: black;
}
h1 {
font-family: sans-serif;
font-size: 2em;
font-weight: bold;
margin: 2px 5px 5px 5px
}
.message {
font-family: sans-serif;
font-size: 1.2em;
padding: 0 4px 0 4px;
}
.mock {
color: gray;
}
#access_code_display {
font-family: sans-serif;
font-size: 200%;
margin: 0 0 0 24px;
padding: 0 4px 0 4px;
border-style: solid;
background-color: lightgray;
display: inline-block;
}
.hostlist {
margin: 0;
border: #D9D9D9 1px solid;
border-radius: 2px;
}
.remoting_body {
-webkit-user-select: none;
margin: 0;
padding: 0;
overflow: auto;
}
.status_msg {
margin: 5px;
}
.debug_log {
-webkit-user-select: text;
padding: 0px;
margin: 0px;
position: fixed;
bottom: 0px;
width: 100%;
height: 150px;
overflow: auto;
font-family: monospace;
font-weight: bold;
font-size: small;
border: 2px solid #ffffff;
display: none;
opacity: 0.9;
background-color: #ffffff;
z-index: 1;
}
.debug_log_toggle {
line-height: 0.8em;
float: right;
}
.scale_to_fit_toggle {
line-height: 0.8em;
float: right;
}
.plugin-scroll-panel {
-webkit-user-select: none;
overflow: auto;
width: 100%;
}
.gaia_font {
font-family: Arial, Helvetica, sans-serif;
}
.page h1 {
-webkit-padding-end: 24px;
-webkit-user-select: none;
border-bottom: 1px solid #eeeeee;
color: #53637d;
font-size: 200%;
font-weight: normal;
margin: 0;
padding-bottom: 4px;
padding-top: 13px;
text-shadow: white 0 1px 2px;
}
section {
-webkit-box-orient: horizontal;
border-bottom: 1px solid #eeeeee;
display: -webkit-box;
margin-top: 17px;
padding-bottom: 20px;
}
section > h3 {
font-size: 105%;
font-weight: bold;
margin: 0;
vertical-align: middle;
width: 160px;
}
section > div:only-of-type {
-webkit-box-flex: 1;
}
div.page section:last-child {
border-bottom: none;
}
button {
-webkit-border-radius: 2px;
-webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
-webkit-user-select: none;
background: -webkit-linear-gradient(#fafafa, #f4f4f4 40%, #e5e5e5);
border: 1px solid #aaa;
color: #444;
font-size: inherit;
margin-bottom: 0px;
min-width: 4em;
padding: 3px 12px 3px 12px;
}
button:hover {
-webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.2);
background: #ebebeb -webkit-linear-gradient(#fefefe, #f8f8f8 40%, #e9e9e9);
border-color: #999;
color: #222;
}
button:active {
-webkit-box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.2);
background: #ebebeb -webkit-linear-gradient(#f4f4f4, #efefef 40%, #dcdcdc);
color: #333;
}
button[disabled], button[disabled]:hover {
-webkit-box-shadow: none;
background: -webkit-linear-gradient(#fafafa, #f4f4f4 40%, #e5e5e5);
border-color: #aaa;
color: #888;
form {
display: inline;
}

@ -8,6 +8,9 @@
// to copy and paste a code, but that does not support extension URL schemes
// quite yet. Instead, we currently use the native app flow with an
// authorization code that the user must cut/paste.
var remoting = chrome.extension.getBackgroundPage().remoting;
function OAuth2() {
this.OAUTH2_REFRESH_TOKEN_NAME = 'oauth2_refresh_token';

@ -2,91 +2,77 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
"use strict";
// TODO(ajwong): This seems like a bad idea to share the exact same object
// with the background page. Why are we doing it like this?
var remoting = chrome.extension.getBackgroundPage().remoting;
remoting.CLIENT_MODE='client';
remoting.HOST_MODE='host';
remoting.PLUGIN_MIMETYPE='HOST_PLUGIN_MIMETYPE';
remoting.XMPP_LOGIN_NAME = 'xmpp_login';
remoting.HOST_PLUGIN_ID = 'host-plugin-id';
XMPP_LOGIN_NAME = 'xmpp_login';
XMPP_TOKEN_NAME = 'xmpp_token';
HOST_PLUGIN_ID = 'host_plugin_id';
window.addEventListener("load", init_, false);
function hasClass(element, cls) {
return element.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
function showElement(element, visible) {
if (visible) {
if (hasClass(element, 'display-inline')) {
element.style.display = 'inline';
} else {
element.style.display = 'block';
}
} else {
element.style.display = 'none';
}
}
function showElementById(id, visible) {
showElement(document.getElementById(id), visible);
}
// This code moved into this subroutine (instead of being inlined in
// updateAuthStatus_() because of bug in V8.
// http://code.google.com/p/v8/issues/detail?id=1423
function updateControls_(disable) {
var authStatusControls =
document.getElementsByClassName('auth-status-control');
for (var i = 0; i < authStatusControls.length; ++i) {
authStatusControls[i].disabled = disable;
}
}
function updateAuthStatus_() {
var oauth2_status = document.getElementById('oauth2_status');
if (remoting.oauth2.isAuthenticated()) {
oauth2_status.innerText = 'OK';
oauth2_status.style.color = 'green';
document.getElementById('oauth2_code_button').style.display = 'none';
document.getElementById('oauth2_clear_button').style.display = 'inline';
document.getElementById('oauth2_form').style.display = 'none';
var oauthValid = remoting.oauth2.isAuthenticated();
if (!oauthValid) {
document.getElementById('oauth2-code').value = "";
}
showElementById('oauth2-submit-button', false);
showElementById('oauth2-code', !oauthValid);
showElementById('oauth2-code-button', !oauthValid);
showElementById('oauth2-clear-button', oauthValid);
var loginName = remoting.getItem(remoting.XMPP_LOGIN_NAME);
if (loginName) {
document.getElementById('current-email').innerText = loginName;
}
showElementById('current-email', loginName);
showElementById('change-email-button', loginName);
showElementById('new-email', !loginName);
showElementById('email-submit-button', !loginName);
var disableControls = !(loginName && oauthValid);
var authPanel = document.getElementById('auth-panel');
if (disableControls) {
authPanel.style.backgroundColor = 'rgba(204, 0, 0, 0.15)';
} else {
oauth2_status.innerText = 'Unauthorized';
oauth2_status.style.color = 'red';
document.getElementById('oauth2_code_button').style.display = 'inline';
document.getElementById('oauth2_clear_button').style.display = 'none';
document.getElementById('oauth2_form').style.display = 'inline';
authPanel.style.backgroundColor = 'rgba(0, 204, 102, 0.15)';
}
var xmpp_status = document.getElementById('xmpp_status');
if (remoting.getItem(XMPP_TOKEN_NAME) && remoting.getItem(XMPP_LOGIN_NAME)) {
document.getElementById('xmpp_clear').style.display = 'inline';
document.getElementById('xmpp_form').style.display = 'none';
xmpp_status.innerText = 'OK';
xmpp_status.style.color = 'green';
} else {
document.getElementById('xmpp_clear').style.display = 'none';
document.getElementById('xmpp_form').style.display = 'inline';
xmpp_status.innerText = 'Unauthorized';
xmpp_status.style.color = 'red';
}
var current_email = document.getElementById('current_email');
if (remoting.getItem(XMPP_LOGIN_NAME)) {
oauth2_status.style.color = 'green';
current_email.innerText = remoting.getItem(XMPP_LOGIN_NAME);
} else {
oauth2_status.style.color = 'red';
current_email.innerText = 'missing e-mail';
}
}
function clientLoginError_(xhr) {
// If there's an error URL, load it into an iframe.
var url_line = xhr.responseText.match('Url=.*');
if (url_line) {
url = url_line[0].substr(4);
var error_frame = document.getElementById('xmpp_error');
error_frame.src = url;
error_frame.style.display = 'block';
}
var log_msg = 'Client Login failed. Status: ' + xhr.status +
' body: ' + xhr.responseText;
console.log(log_msg);
var last_error = document.getElementById('xmpp_last_error');
last_error.innerText = log_msg;
last_error.style.display = 'inline';
}
function resetXmppErrors_() {
document.getElementById('xmpp_captcha').style.display = 'none';
document.getElementById('xmpp_error').style.display = 'none';
document.getElementById('xmpp_last_error').style.display = 'none';
}
function displayCaptcha_(form, url, token) {
form['xmpp_captcha_token'].value = token;
document.getElementById('xmpp_captcha_img').src = url;
document.getElementById('xmpp_captcha').style.display = 'inline';
}
function readAndClearCaptcha_(form) {
var captcha_token = form['xmpp_captcha_token'].value;
form['xmpp_captcha_token'].value = '';
resetXmppErrors_();
return [captcha_token, form['xmpp_captcha_result'].value];
}
function initAuthPanel_() {
updateAuthStatus_();
resetXmppErrors_();
updateControls_(disableControls);
}
function initBackgroundFuncs_() {
@ -96,63 +82,21 @@ function initBackgroundFuncs_() {
remoting.oauth2 = new OAuth2();
}
function authorizeXmpp(form) {
var xhr = new XMLHttpRequest();
var captcha_result = readAndClearCaptcha_(form);
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) {
return;
}
if (xhr.status == 200) {
var auth_line = xhr.responseText.match('Auth=.*');
if (!auth_line) {
clientLoginError_(xhr);
return;
}
remoting.setItem(XMPP_TOKEN_NAME, auth_line[0].substr(5));
remoting.setItem(XMPP_LOGIN_NAME, form['xmpp_username'].value);
updateAuthStatus_();
} else if (xhr.status == 403) {
var error_line = xhr.responseText.match('Error=.*');
if (error_line && error_line == 'Error=CaptchaRequired') {
var captcha_token = xhr.responseText.match('CaptchaToken=.*');
var captcha_url = xhr.responseText.match('CaptchaUrl=.*');
displayCaptcha_(
form,
'https://www.google.com/accounts/' + captcha_url[0].substr(11),
captcha_token[0].substr(13));
return;
}
clientLoginError_(xhr);
} else {
clientLoginError_(xhr);
}
};
xhr.open('POST', 'https://www.google.com/accounts/ClientLogin', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
var post_data =
'accountType=HOSTED_OR_GOOGLE' +
'&service=chromiumsync' +
'&source=remoting-webapp' +
'&Email=' + encodeURIComponent(form['xmpp_username'].value) +
'&Passwd=' + encodeURIComponent(form['xmpp_password'].value);
if (captcha_result[0]) {
post_data += '&logintoken=' + encodeURIComponent(captcha_result[0]) +
'&logincaptcha=' + encodeURIComponent(captcha_result[1]);
}
xhr.send(post_data);
}
function setEmail(form) {
remoting.setItem(XMPP_LOGIN_NAME, form['new_email'].value);
function setEmail(value) {
remoting.setItem(remoting.XMPP_LOGIN_NAME, value);
updateAuthStatus_();
}
function authorizeOAuth2(code) {
remoting.oauth2.exchangeCodeForToken(code, updateAuthStatus_);
function exchangedCodeForToken_() {
if (!remoting.oauth2.isAuthenticated()) {
alert("Your OAuth2 token was invalid. Please try again.");
}
updateAuthStatus_();
}
function authorizeOAuth2() {
remoting.oauth2.exchangeCodeForToken(
document.getElementById('oauth2-code').value, exchangedCodeForToken_);
}
function clearOAuth2() {
@ -160,33 +104,46 @@ function clearOAuth2() {
updateAuthStatus_();
}
function clearXmpp() {
remoting.removeItem(XMPP_TOKEN_NAME);
updateAuthStatus_();
function handleOAuth2CodeChange() {
var hasCode = document.getElementById('oauth2-code').value.length > 0;
showElementById('oauth2-submit-button', hasCode);
showElementById('oauth2-code-button', !hasCode);
}
// Show the div with id |mode| and hide those with other ids in |modes|.
function setMode_(mode, modes) {
for (var i = 0; i < modes.length; ++i) {
var div = document.getElementById(modes[i]);
if (mode == modes[i]) {
div.style.display = 'block';
} else {
div.style.display = 'none';
}
showElement(modes[i], mode == modes[i].id);
}
}
function init() {
function init_() {
initBackgroundFuncs_();
initAuthPanel_();
updateAuthStatus_();
setHostMode('unshared');
setClientMode('unconnected');
setGlobalMode(remoting.getItem('startup-mode', 'host'));
setGlobalMode(remoting.getItem('startup-mode', remoting.HOST_MODE));
}
function setGlobalMode(mode) {
setMode_(mode, ['host', 'client']);
var elementsToShow = [];
var elementsToHide = [];
var hostElements = document.getElementsByClassName('host-element');
var clientElements = document.getElementsByClassName('client-element');
if (mode == remoting.HOST_MODE) {
elementsToShow = hostElements;
elementsToHide = clientElements;
} else {
elementsToShow = clientElements;
elementsToHide = hostElements;
}
for (var i = 0; i < elementsToShow.length; ++i) {
showElement(elementsToShow[i], true);
}
for (var i = 0; i < elementsToHide.length; ++i) {
showElement(elementsToHide[i], false);
}
}
function setGlobalModePersistent(mode) {
@ -195,14 +152,15 @@ function setGlobalModePersistent(mode) {
}
function setHostMode(mode) {
setMode_(mode, ['unshared',
'preparing_to_share',
'ready_to_share',
'shared']);
var section = document.getElementById('host-section');
var modes = section.getElementsByClassName('mode');
setMode_(mode, modes);
}
function setClientMode(mode) {
setMode_(mode, ['unconnected', 'connecting', 'connect_failed']);
var section = document.getElementById('client-section');
var modes = section.getElementsByClassName('mode');
setMode_(mode, modes);
}
function tryShare() {
@ -217,27 +175,27 @@ function tryShare() {
return;
}
var div = document.getElementById('plugin_wrapper');
var div = document.getElementById('plugin-wrapper');
var plugin = document.createElement('embed');
plugin.setAttribute('type', 'HOST_PLUGIN_MIMETYPE');
plugin.setAttribute('type', remoting.PLUGIN_MIMETYPE);
plugin.setAttribute('hidden', 'true');
plugin.setAttribute('id', HOST_PLUGIN_ID);
plugin.setAttribute('id', remoting.HOST_PLUGIN_ID);
div.appendChild(plugin);
plugin.onStateChanged = onStateChanged_;
plugin.connect(remoting.getItem(XMPP_LOGIN_NAME),
plugin.connect(remoting.getItem(remoting.XMPP_LOGIN_NAME),
'oauth2:' + remoting.oauth2.getAccessToken());
}
function onStateChanged_() {
var plugin = document.getElementById(HOST_PLUGIN_ID);
var plugin = document.getElementById(remoting.HOST_PLUGIN_ID);
var state = plugin.state;
if (state == plugin.REQUESTED_ACCESS_CODE) {
setHostMode('preparing_to_share');
setHostMode('preparing-to-share');
} else if (state == plugin.RECEIVED_ACCESS_CODE) {
var access_code = plugin.accessCode;
var access_code_display = document.getElementById('access_code_display');
access_code_display.innerText = access_code;
setHostMode('ready_to_share');
var accessCode = plugin.accessCode;
var accessCodeDisplay = document.getElementById('access-code-display');
accessCodeDisplay.innerText = accessCode;
setHostMode('ready-to-share');
} else if (state == plugin.CONNECTED) {
setHostMode('shared');
} else if (state == plugin.DISCONNECTED) {
@ -249,29 +207,29 @@ function onStateChanged_() {
}
function cancelShare() {
var plugin = document.getElementById(HOST_PLUGIN_ID);
var plugin = document.getElementById(remoting.HOST_PLUGIN_ID);
plugin.disconnect();
}
function startSession_() {
remoting.username = remoting.getItem(XMPP_LOGIN_NAME);
remoting.username = remoting.getItem(remoting.XMPP_LOGIN_NAME);
document.location = 'remoting_session.html';
}
function showConnectError_(responseCode, responseString) {
var invalid = document.getElementById('invalid_access_code');
var other = document.getElementById('other_connect_error');
var invalid = document.getElementById('invalid-access-code');
var other = document.getElementById('other-connect-error');
if (responseCode == 404) {
invalid.style.display = 'block';
other.style.display = 'none';
} else {
invalid.style.display = 'none';
other.style.display = 'block';
var responseNode = document.getElementById('server_response');
var responseNode = document.getElementById('server-response');
responseNode.innerText = responseString + ' (' + responseCode + ')';
}
remoting.accessCode = '';
setClientMode('connect_failed');
setClientMode('connect-failed');
}
function parseServerResponse_(xhr) {
@ -293,7 +251,7 @@ function normalizeAccessCode(accessCode) {
return accessCode.replace(/^\s+|\s+$/, '');
}
function resolveSupportId(support_id) {
function resolveSupportId(supportId) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) {
@ -304,25 +262,25 @@ function resolveSupportId(support_id) {
xhr.open('GET',
'https://www.googleapis.com/chromoting/v1/support-hosts/' +
encodeURIComponent(support_id),
encodeURIComponent(supportId),
true);
xhr.setRequestHeader('Authorization',
'OAuth ' + remoting.oauth2.getAccessToken());
xhr.send(null);
}
function tryConnect(accessCode) {
function tryConnect() {
if (remoting.oauth2.needsNewAccessToken()) {
remoting.oauth2.refreshAccessToken(function() {
if (remoting.oauth2.needsNewAccessToken()) {
// If we still need it, we're going to infinite loop.
throw "Unable to get access token";
}
tryConnect(accessCode);
tryConnect();
});
return;
}
var accessCode = document.getElementById('access-code-entry').value;
remoting.accessCode = accessCode;
// TODO(jamiewalch): Since the mapping from (SupportId, HostSecret) to
// AccessCode is not yet defined, assume it's hyphen-separated for now.

@ -0,0 +1,73 @@
/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Elements */
body {
margin: 0;
overflow: auto;
padding: 0;
-webkit-user-select: none;
}
/* Ids */
#debug-log {
background-color: white;
bottom: 0;
border-top: 1px solid black;
display: none;
font-family: monospace;
font-weight: bold;
font-size: small;
height: 150px;
margin: 0;
opacity: 0.85;
overflow: auto;
padding: 0;
position: fixed;
width: 100%;
z-index: 100;
-webkit-user-select: text;
}
#plugin-scroll-panel {
overflow: auto;
width: 100%;
-webkit-user-select: none;
}
#session-buttons {
float: right;
}
#session-controls {
background-color: white;
border-bottom: solid 1px black;
height: 1.5em;
left: 0;
opacity: 0.85;
position: fixed;
top: 0;
width: 100%;
z-index: 100;
}
#session-controls-padding {
/*
Maintains space for session-controls so that the display initially appears
lower than the controls, since session-controls is position:fixed.
*/
height: 1.5em;
}
#status-msg {
/*
clear: both; forces the session-controls div to size appropriately for
session-buttons.
*/
clear: both;
font-family: monospace;
font-size: small;
margin: 5px;
}

@ -7,24 +7,30 @@ found in the LICENSE file.
<html>
<head>
<title id="title">Remoting Session</title>
<link rel="stylesheet" type="text/css" href="main.css" />
<script type="text/javascript" src="oauth2.js"></script>
<script type="text/javascript" src="remoting_session.js"></script>
<title>Chromoting Session</title>
<link rel="shortcut icon" href="chromoting128.png" />
<link rel="stylesheet" href="main.css" />
<link rel="stylesheet" href="remoting_session.css" />
<script src="oauth2.js"></script>
<script src="remoting_session.js"></script>
</head>
<body class="remoting_body" onload="init();">
<div id="status_msg_div">
<span id="status_msg" class="status_msg">Initializing...</span>
<input type="button" value="Scale to fit" class="scale_to_fit_toggle"
id="scale_to_fit_toggle" onclick="toggleScaleToFit();"/>
<input type="button" value="Show Debug Log" class="debug_log_toggle"
id="debug_log_toggle" onclick="toggleDebugLog();"/>
<body id="session-body">
<div id="session-controls">
<form id="session-buttons">
<input id="scale-to-fit-toggle" type="button" value="Scale to fit"
onclick="toggleScaleToFit();"/>
<input id="debug-log-toggle" type="button" value="Show Debug Log"
onclick="toggleDebugLog(); return false;"/>
</form>
<span id="status-msg">Initializing...</span>
</div>
<div id="plugin_scroll_panel" class="plugin-scroll-panel">
<div id="session-controls-padding">
</div>
<div id="plugin-scroll-panel">
<embed name="remoting" id="remoting"
src="about://none" type="pepper-application/x-chromoting">
</div>
<div id="debug_log" class="debug_log">
<div id="debug-log">
</div>
</body>
</html>

@ -29,6 +29,8 @@ remoting.connectMethod = 'sandboxed';
remoting.httpXmppProxy =
'https://chromoting-httpxmpp-oauth2-dev.corp.google.com';
window.addEventListener("load", init_, false);
// This executes a poll loop on the server for more Iq packets, and feeds them
// to the plugin.
function feedIq() {
@ -116,7 +118,7 @@ function checkVersion(plugin) {
plugin.apiVersion >= remoting.apiMinVersion;
}
function init() {
function init_() {
// Kick off the connection.
var plugin = document.getElementById('remoting');
@ -169,8 +171,8 @@ function init() {
}
function toggleDebugLog() {
debugLog = document.getElementById('debug_log');
toggleButton = document.getElementById('debug_log_toggle');
debugLog = document.getElementById('debug-log');
toggleButton = document.getElementById('debug-log-toggle');
if (!debugLog.style.display || debugLog.style.display == 'none') {
debugLog.style.display = 'block';
@ -183,7 +185,7 @@ function toggleDebugLog() {
function toggleScaleToFit() {
remoting.scaleToFit = !remoting.scaleToFit;
document.getElementById('scale_to_fit_toggle').value =
document.getElementById('scale-to-fit-toggle').value =
remoting.scaleToFit ? 'No scaling' : 'Scale to fit';
remoting.plugin.setScaleToFit(remoting.scaleToFit);
}
@ -244,7 +246,7 @@ function setClientStateMessage(message) {
remoting.messageId++;
// Update the status message.
var msg = document.getElementById('status_msg');
var msg = document.getElementById('status-msg');
msg.innerText = message;
msg.style.opacity = 1;
msg.style.display = '';
@ -260,7 +262,7 @@ function setClientStateMessageFade(message, duration) {
setClientStateMessage(message);
// Set message duration.
window.setTimeout("fade('status_msg', " + remoting.messageId + ', ' +
window.setTimeout("fade('status-msg', " + remoting.messageId + ', ' +
'100, 10, 200)',
duration);
}
@ -292,7 +294,7 @@ function fade(name, id, val, delta, delay) {
if (newVal > 0) {
// Decrease opacity and set timer for next fade event.
e.style.opacity = newVal / 100;
window.setTimeout("fade('status_msg', " + id + ', ' + newVal + ', ' +
window.setTimeout("fade('status-msg', " + id + ', ' + newVal + ', ' +
delta + ', ' + delay + ')',
delay);
} else {
@ -317,7 +319,7 @@ function debugInfoCallback(msg) {
* @param {string} message The debug info to add to the log.
*/
function addToDebugLog(message) {
var debugLog = document.getElementById('debug_log');
var debugLog = document.getElementById('debug-log');
// Remove lines from top if we've hit our max log size.
if (debugLog.childNodes.length == MAX_DEBUG_LOG_SIZE) {
@ -346,22 +348,22 @@ function updateStatusBarStats() {
if (videoBandwidth < 1024) {
units = 'Bps';
} else if (videoBandwidth < 1048576) {
units = 'KBps';
units = 'KiBps';
videoBandwidth = videoBandwidth / 1024;
} else if (videoBandwidth < 1073741824) {
units = 'MBps';
units = 'MiBps';
videoBandwidth = videoBandwidth / 1048576;
} else {
units = 'GBps';
units = 'GiBps';
videoBandwidth = videoBandwidth / 1073741824;
}
setClientStateMessage(
'Video stats: bandwidth: ' + videoBandwidth.toFixed(2) + units +
', Latency: capture: ' + videoCaptureLatency.toFixed(2) + 'ms' +
', encode: ' + videoEncodeLatency.toFixed(2) + 'ms' +
', decode: ' + videoDecodeLatency.toFixed(2) + 'ms' +
', render: ' + videoRenderLatency.toFixed(2) + 'ms');
'Bandwidth: ' + videoBandwidth.toFixed(2) + units +
', Capture: ' + videoCaptureLatency.toFixed(2) + 'ms' +
', Encode: ' + videoEncodeLatency.toFixed(2) + 'ms' +
', Decode: ' + videoDecodeLatency.toFixed(2) + 'ms' +
', Render: ' + videoRenderLatency.toFixed(2) + 'ms');
// Update the stats once per second.
window.setTimeout('updateStatusBarStats()', 1000);