Commit 81d05c56 authored by kelvinp's avatar kelvinp Committed by Commit bot

[AppRemoting] Implement ConnectionDroppedDialog.

This CL implements a ConnectionDroppedDialog using HTML5 dialog element.
The dialog will be shown to the user whenever a connection is dropped.

BUG=486888

Review URL: https://codereview.chromium.org/1146833002

Cr-Commit-Position: refs/heads/master@{#330849}
parent 4394f60e
......@@ -47,6 +47,7 @@
'<(DEPTH)/remoting/webapp/app_remoting/html/template_lg.html',
'ar_main_template_files': [
'webapp/base/html/client_plugin.html',
'webapp/base/html/connection_dropped_dialog.html',
'webapp/app_remoting/html/context_menu.html',
'webapp/app_remoting/html/idle_dialog.html',
],
......
......@@ -563,6 +563,12 @@
<message desc="Button to allow the user to indicate that they are no longer using the service." name="IDS_IDLE_DISCONNECT">
Disconnect now
</message>
<message desc="Button to restart the app after the connection is dropped." name="IDS_RESTART_BUTTON">
Restart
</message>
<message desc="Message show to the user when the connection is dropped." name="IDS_ERROR_CONNECTION_DROPPED">
Connection to the remote server has been lost. This app is not available offline.
</message>
<if expr="is_android or is_ios">
<message desc="Button to show or hide the on-screen keyboard." name="IDS_SHOW_HIDE_KEYBOARD" formatter_data="android_java">
......
......@@ -9,11 +9,15 @@
width: 100%;
}
#idle-dialog .kd-modaldialog,
#auth-dialog .kd-modaldialog {
.app-remoting .kd-modaldialog {
/*
* kd-modaldialog uses outline, which doesn't affect the bounding box, and so
* doesn't work well when adjusting the window shape.
*/
border: 1px solid gray;
}
#connection-dropped-dialog {
margin: 0px;
position: absolute;
}
......@@ -5,11 +5,12 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<html class="full-height">
<html class="full-height app-remoting">
<head>
<meta charset="utf-8">
<link rel="icon" type="image/png" href="icon16.png">
<link rel="stylesheet" href="ar_main.css">
<link rel="stylesheet" href="ar_dialog.css">
<link rel="stylesheet" href="connection_stats.css">
<link rel="stylesheet" href="context_menu.css">
<link rel="stylesheet" href="main.css">
......@@ -38,6 +39,7 @@ found in the LICENSE file.
<meta-include src="webapp/app_remoting/html/context_menu.html"/>
<meta-include src="webapp/app_remoting/html/idle_dialog.html"/>
<meta-include src="webapp/base/html/connection_dropped_dialog.html"/>
<div id="statistics" dir="ltr" class="selectable" hidden>
</div> <!-- statistics -->
......
......@@ -74,8 +74,9 @@ remoting.AppConnectedView = function(containerElement, connectionInfo) {
this.onDesktopSizeChanged_.bind(this));
/** @private */
this.disposables_ = new base.Disposables(
baseView, windowShapeHook, desktopSizeHook, this.contextMenu_);
this.disposables_ =
new base.Disposables(baseView, windowShapeHook, desktopSizeHook,
this.contextMenu_, menuAdapter);
/** @private */
this.supportsGoogleDrive_ = this.plugin_.hasCapability(
......
......@@ -180,9 +180,8 @@ remoting.AppRemotingActivity.prototype.onDisconnected = function(error) {
if (error.isNone()) {
chrome.app.window.current().close();
} else {
this.showErrorMessage_(error);
this.onConnectionDropped_();
}
this.cleanup_();
};
/**
......@@ -194,6 +193,32 @@ remoting.AppRemotingActivity.prototype.onConnectionFailed = function(error) {
this.cleanup_();
};
/** @private */
remoting.AppRemotingActivity.prototype.onConnectionDropped_ = function() {
var rootElement = /** @type {HTMLDialogElement} */ (
document.getElementById('connection-dropped-dialog'));
var dialog = new remoting.Html5ModalDialog({
dialog: rootElement,
primaryButton: rootElement.querySelector('.restart-button'),
secondaryButton: rootElement.querySelector('.close-button'),
closeOnEscape: false
});
var that = this;
dialog.show().then(function(/** remoting.MessageDialog.Result */ result) {
if (result === remoting.MessageDialog.Result.PRIMARY) {
// Hide the windows of the remote application with setDesktopRects([])
// before tearing down the plugin.
remoting.windowShape.setDesktopRects([]);
that.cleanup_();
that.start();
} else {
chrome.app.window.current().close();
}
});
};
/**
* @param {!remoting.Error} error The error to be localized and displayed.
* @private
......
......@@ -18,7 +18,9 @@ var remoting = remoting || {};
*/
remoting.ContextMenuChrome = function() {};
remoting.ContextMenuChrome.prototype.dispose = function() {};
remoting.ContextMenuChrome.prototype.dispose = function() {
chrome.contextMenus.removeAll();
};
/**
* @param {string} id An identifier for the menu entry.
......
<!--
Copyright 2015 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.
-->
<dialog id='connection-dropped-dialog' class='kd-modaldialog'>
<div class='error-state' i18n-content='ERROR_CONNECTION_DROPPED'></div>
<div class='box-spacer'></div>
<div class='button-row'>
<button class='restart-button' i18n-content='RESTART_BUTTON'
autofocus='autofocus'></button>
<button class='close-button' i18n-content='CLOSE'></button>
</div>
</dialog>
......@@ -158,6 +158,99 @@ remoting.MessageDialog.prototype.onClicked_ = function(result) {
this.dispose();
};
/**
* A promise-based dialog implementation using the <dialog> element.
*
* @param {remoting.Html5ModalDialog.Params} params
* @constructor
*
* @implements {remoting.WindowShape.ClientUI}
* @implements {base.Disposable}
*/
remoting.Html5ModalDialog = function(params) {
/** @private */
this.dialog_ = params.dialog;
/** @private {base.Disposables} */
this.eventHooks_ = new base.Disposables(
new base.DomEventHook(
this.dialog_, 'cancel', this.onCancel_.bind(this), false),
new base.DomEventHook(
params.primaryButton, 'click',
this.close.bind(this, remoting.MessageDialog.Result.PRIMARY), false)
);
if (params.secondaryButton) {
this.eventHooks_.add(new base.DomEventHook(
params.secondaryButton, 'click',
this.close.bind(this, remoting.MessageDialog.Result.SECONDARY), false));
}
/** @private */
this.closeOnEscape_ = Boolean(params.closeOnEscape);
/** @private {base.Deferred} */
this.deferred_ = null;
};
remoting.Html5ModalDialog.prototype.dispose = function() {
base.dispose(this.eventHooks_);
this.eventHookes_ = null;
};
/**
* @return {Promise<remoting.MessageDialog.Result>} Promise that resolves with
* the button clicked.
*/
remoting.Html5ModalDialog.prototype.show = function() {
base.debug.assert(this.deferred_ === null);
this.deferred_ = new base.Deferred();
this.dialog_.showModal();
remoting.windowShape.registerClientUI(this);
remoting.windowShape.centerToDesktop(this.dialog_);
return this.deferred_.promise();
};
/** @param {Event} e */
remoting.Html5ModalDialog.prototype.onCancel_ = function(e) {
e.preventDefault();
if (this.closeOnEscape_) {
this.close(remoting.MessageDialog.Result.CANCEL);
}
};
/**
* @param {remoting.MessageDialog.Result} result
*/
remoting.Html5ModalDialog.prototype.close = function(result) {
if (!this.dialog_.open) {
return;
}
this.dialog_.close();
this.deferred_.resolve(result);
this.deferred_ = null;
remoting.windowShape.unregisterClientUI(this);
};
remoting.Html5ModalDialog.prototype.addToRegion = function(rects) {
var rect = /** @type {ClientRect} */(this.dialog_.getBoundingClientRect());
// If the dialog is repositioned by setting the left and top, it takes a while
// for getBoundingClientRect() to update the rectangle.
var left = this.dialog_.style.left;
var top = this.dialog_.style.top;
rects.push({
left: (left === '') ? rect.left : parseInt(left, 10),
top: (top === '') ? rect.top : parseInt(top, 10),
width: rect.width,
height: rect.height
});
};
/**
* @param {Function} cancelCallback The callback to invoke when the user clicks
* on the cancel button.
......@@ -194,5 +287,28 @@ remoting.ConnectingDialog.prototype.hide = function() {
*/
remoting.MessageDialog.Result = {
PRIMARY: 0,
SECONDARY: 1
};
\ No newline at end of file
SECONDARY: 1,
CANCEL: 2 // User presses the escape button.
};
/**
* Parameters for the remoting.Html5ModalDialog constructor. Unless otherwise
* noted, all parameters are optional.
*
* dialog: (required) The HTML dialog element.
*
* primaryButton: (required) The HTML element of the primary button.
*
* secondaryButton: The HTML element of the secondary button.
*
* closeOnEscape: Whether the user can dismiss the dialog by pressing the escape
* key. Default to false.
*
* @typedef {{
* dialog: HTMLDialogElement,
* primaryButton:HTMLElement,
* secondaryButton:(HTMLElement|undefined),
* closeOnEscape:(boolean|undefined)
* }}
*/
remoting.Html5ModalDialog.Params;
\ No newline at end of file
......@@ -90,8 +90,8 @@ remoting.WindowShape.prototype.centerToDesktop = function(element) {
var rect = element.getBoundingClientRect();
var left = (desktop.right - desktop.left - rect.width) / 2 + desktop.left;
var top = (desktop.bottom - desktop.top - rect.height) / 2 + desktop.top;
element.style.left = left + 'px';
element.style.top = top + 'px';
element.style.left = Math.round(left) + 'px';
element.style.top = Math.round(top) + 'px';
this.updateClientWindowShape();
};
......
......@@ -520,6 +520,7 @@ ar_main_template = "app_remoting/html/template_lg.html"
ar_main_template_files = [
"base/html/client_plugin.html",
"base/html/connection_dropped_dialog.html",
"app_remoting/html/context_menu.html",
"app_remoting/html/idle_dialog.html",
]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment