Chromium Code Reviews| Index: remoting/webapp/base/js/application.js |
| diff --git a/remoting/webapp/base/js/application.js b/remoting/webapp/base/js/application.js |
| index bcd6cf122f2d5a5471fd16926e2e740863c23869..11fec3651a3ec7ed1d6728231391202990509e11 100644 |
| --- a/remoting/webapp/base/js/application.js |
| +++ b/remoting/webapp/base/js/application.js |
| @@ -15,10 +15,13 @@ var remoting = remoting || {}; |
| /** |
| * @param {Array<string>} appCapabilities Array of application capabilities. |
| * @constructor |
| + * @implements {remoting.ApplicationInterface} |
| */ |
| remoting.Application = function(appCapabilities) { |
| - /** @private {remoting.Application.Delegate} */ |
| - this.delegate_ = null; |
| + // Create global factories. |
| + remoting.ClientPlugin.factory = new remoting.DefaultClientPluginFactory(); |
| + remoting.SessionConnector.factory = |
| + new remoting.DefaultSessionConnectorFactory(); |
| /** @private {Array<string>} */ |
| this.appCapabilities_ = [ |
| @@ -29,26 +32,23 @@ remoting.Application = function(appCapabilities) { |
| // Append the app-specific capabilities. |
| this.appCapabilities_.push.apply(this.appCapabilities_, appCapabilities); |
| - /** @private {remoting.SessionConnector} */ |
| - this.sessionConnector_ = null; |
| + /** @protected {remoting.SessionConnector} */ |
| + this.sessionConnector_ = remoting.SessionConnector.factory.createConnector( |
| + document.getElementById('client-container'), |
| + this.onConnected_.bind(this), |
| + this.onError_.bind(this), |
| + this.onConnectionFailed_.bind(this), |
| + this.appCapabilities_); |
| /** @private {base.Disposable} */ |
| this.sessionConnectedHooks_ = null; |
| }; |
| /** |
| - * @param {remoting.Application.Delegate} appDelegate The delegate that |
| - * contains the app-specific functionality. |
| + * @return {remoting.SessionConnector} The session connector. |
| */ |
| -remoting.Application.prototype.setDelegate = function(appDelegate) { |
| - this.delegate_ = appDelegate; |
| -}; |
| - |
| -/** |
| - * @return {string} Application product name to be used in UI. |
| - */ |
| -remoting.Application.prototype.getApplicationName = function() { |
| - return this.delegate_.getApplicationName(); |
| +remoting.Application.prototype.getSessionConnector = function() { |
| + return this.sessionConnector_; |
| }; |
| /** |
| @@ -60,18 +60,33 @@ remoting.Application.prototype.hasCapability = function(capability) { |
| return capabilities.indexOf(capability) != -1; |
| }; |
| +/* Disconnect the remoting client. */ |
| +remoting.Application.prototype.disconnect = function() { |
| + if (remoting.clientSession) { |
| + remoting.clientSession.disconnect(remoting.Error.none()); |
| + console.log('Disconnected.'); |
| + } |
| +}; |
| + |
| +/* Public method to exit the application. */ |
| +remoting.Application.prototype.quit = function() { |
| + this.exitApplication_(); |
| +}; |
| + |
| +/** |
| + * Close the main window when quitting the application. This should be called |
| + * by exitApplication() in the subclass. |
| + * @protected |
| + */ |
| +remoting.Application.prototype.exit_ = function() { |
|
Jamie
2015/03/26 01:54:30
Having both exit_ and quit is confusing. Perhaps e
garykac
2015/03/26 16:38:11
Changed name to closeMainWindow_ since I like havi
|
| + chrome.app.window.current().close(); |
| +}; |
| + |
| /** |
| * Initialize the application and register all event handlers. After this |
| * is called, the app is running and waiting for user events. |
| - * |
| - * @return {void} Nothing. |
| */ |
| remoting.Application.prototype.start = function() { |
| - // Create global objects. |
| - remoting.ClientPlugin.factory = new remoting.DefaultClientPluginFactory(); |
| - remoting.SessionConnector.factory = |
| - new remoting.DefaultSessionConnectorFactory(); |
| - |
| // TODO(garykac): This should be owned properly rather than living in the |
| // global 'remoting' namespace. |
| remoting.settings = new remoting.Settings(); |
| @@ -79,17 +94,17 @@ remoting.Application.prototype.start = function() { |
| remoting.initGlobalObjects(); |
| remoting.initIdentity(); |
| - this.delegate_.init(); |
| + this.initApplication_(); |
| var that = this; |
| - remoting.identity.getToken().then( |
| - this.delegate_.start.bind(this.delegate_, this.getSessionConnector()) |
| - ).catch(remoting.Error.handler( |
| + remoting.identity.getToken(). |
| + then(this.startApplication_.bind(this)). |
| + catch(remoting.Error.handler( |
| function(/** !remoting.Error */ error) { |
| if (error.hasTag(remoting.Error.Tag.CANCELLED)) { |
| - that.exit(); |
| + that.exitApplication_(); |
| } else { |
| - that.delegate_.signInFailed(error); |
| + that.signInFailed_(error); |
| } |
| } |
| ) |
| @@ -97,82 +112,19 @@ remoting.Application.prototype.start = function() { |
| }; |
| /** |
| - * Quit the application. |
| - */ |
| -remoting.Application.prototype.exit = function() { |
| - this.delegate_.handleExit(); |
| - chrome.app.window.current().close(); |
| -}; |
| - |
| -/** Disconnect the remoting client. */ |
| -remoting.Application.prototype.disconnect = function() { |
| - if (remoting.clientSession) { |
| - remoting.clientSession.disconnect(remoting.Error.none()); |
| - console.log('Disconnected.'); |
| - } |
| -}; |
| - |
| -/** |
| * Called when a new session has been connected. |
| * |
| * @param {remoting.ConnectionInfo} connectionInfo |
| * @return {void} Nothing. |
| + * @protected |
| */ |
| -remoting.Application.prototype.onConnected = function(connectionInfo) { |
| +remoting.Application.prototype.initSession_ = function(connectionInfo) { |
| this.sessionConnectedHooks_ = new base.Disposables( |
| new base.EventHook(connectionInfo.session(), 'stateChanged', |
| this.onSessionFinished_.bind(this)), |
| new base.RepeatingTimer(this.updateStatistics_.bind(this), 1000) |
| ); |
| remoting.clipboard.startSession(); |
| - |
| - this.delegate_.handleConnected(connectionInfo); |
| -}; |
| - |
| -/** |
| - * Called when the current session has been disconnected. |
| - * |
| - * @return {void} Nothing. |
| - */ |
| -remoting.Application.prototype.onDisconnected = function() { |
| - this.delegate_.handleDisconnected(); |
| -}; |
| - |
| -/** |
| - * Called when the current session's connection has failed. |
| - * |
| - * @param {!remoting.Error} error |
| - * @return {void} Nothing. |
| - */ |
| -remoting.Application.prototype.onConnectionFailed = function(error) { |
| - this.delegate_.handleConnectionFailed(this.sessionConnector_, error); |
| -}; |
| - |
| -/** |
| - * Called when an error needs to be displayed to the user. |
| - * |
| - * @param {!remoting.Error} errorTag The error to be localized and displayed. |
| - * @return {void} Nothing. |
| - */ |
| -remoting.Application.prototype.onError = function(errorTag) { |
| - this.delegate_.handleError(errorTag); |
| -}; |
| - |
| -/** |
| - * @return {remoting.SessionConnector} A session connector, creating a new one |
| - * if necessary. |
| - */ |
| -remoting.Application.prototype.getSessionConnector = function() { |
| - // TODO(garykac): Check if this can be initialized in the ctor. |
| - if (!this.sessionConnector_) { |
| - this.sessionConnector_ = remoting.SessionConnector.factory.createConnector( |
| - document.getElementById('client-container'), |
| - this.onConnected.bind(this), |
| - this.onError.bind(this), |
| - this.onConnectionFailed.bind(this), |
| - this.appCapabilities_); |
| - } |
| - return this.sessionConnector_; |
| }; |
| /** |
| @@ -186,7 +138,7 @@ remoting.Application.prototype.onSessionFinished_ = function(state) { |
| switch (state.current) { |
| case remoting.ClientSession.State.CLOSED: |
| console.log('Connection closed by host'); |
| - this.onDisconnected(); |
| + this.onDisconnected_(); |
| break; |
| case remoting.ClientSession.State.FAILED: |
| var error = remoting.clientSession.getError(); |
| @@ -195,14 +147,14 @@ remoting.Application.prototype.onSessionFinished_ = function(state) { |
| if (error === null) { |
| error = remoting.Error.unexpected(); |
| } |
| - this.onError(error); |
| + this.onError_(error); |
| break; |
| default: |
| console.error('Unexpected client plugin state: ' + state.current); |
| // This should only happen if the web-app and client plugin get out of |
| // sync, so MISSING_PLUGIN is a suitable error. |
| - this.onError(new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN)); |
| + this.onError_(new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN)); |
| break; |
| } |
| @@ -219,83 +171,143 @@ remoting.Application.prototype.updateStatistics_ = function() { |
| }; |
| +/* |
| + * remoting.ApplicationInterface |
| + * These functions must be overridden in the subclass. |
| + */ |
| + |
| +/** @return {string} */ |
| +remoting.Application.prototype.getApplicationName = function() { |
| + base.debug.assert(false, "Subclass must override"); |
| +}; |
| + |
| +/** |
| + * @param {!remoting.Error} error |
| + * @protected |
| + */ |
| +remoting.Application.prototype.signInFailed_ = function(error) { |
| + base.debug.assert(false, "Subclass must override"); |
| +}; |
| + |
| +/** @protected */ |
| +remoting.Application.prototype.initApplication_ = function() { |
| + base.debug.assert(false, "Subclass must override"); |
| +}; |
| + |
| +/** |
| + * @param {string} token |
| + * @protected |
| + */ |
| +remoting.Application.prototype.startApplication_ = function(token) { |
| + base.debug.assert(false, "Subclass must override"); |
| +}; |
| + |
| +remoting.Application.prototype.exitApplication_ = function() { |
| + base.debug.assert(false, "Subclass must override"); |
| +}; |
| + |
| +/** |
| + * @param {remoting.ConnectionInfo} connectionInfo |
| + * @protected |
| + */ |
| +remoting.Application.prototype.onConnected_ = function(connectionInfo) { |
| + base.debug.assert(false, "Subclass must override"); |
| +}; |
| + |
| +/** @protected */ |
| +remoting.Application.prototype.onDisconnected_ = function() { |
| + base.debug.assert(false, "Subclass must override"); |
| +}; |
| + |
| +/** |
| + * @param {!remoting.Error} error |
| + * @protected |
| + */ |
| +remoting.Application.prototype.onConnectionFailed_ = function(error) { |
| + base.debug.assert(false, "Subclass must override"); |
| +}; |
| + |
| +/** |
| + * @param {!remoting.Error} error The error to be localized and displayed. |
| + * @protected |
| + */ |
| +remoting.Application.prototype.onError_ = function(error) { |
| + base.debug.assert(false, "Subclass must override"); |
| +}; |
| + |
| + |
| /** |
| + * The interface specifies the methods that a subclass of remoting.Application |
| + * is required implement to override the default behavior. |
| + * |
| * @interface |
| */ |
| -remoting.Application.Delegate = function() {}; |
| +remoting.ApplicationInterface = function() {}; |
| + |
| +/** |
| + * @return {string} Application product name to be used in UI. |
| + */ |
| +remoting.ApplicationInterface.prototype.getApplicationName = function() {}; |
| + |
| +/** |
| + * Report an authentication error to the user. This is called in lieu of |
| + * startApplication() if the user cannot be authenticated or if they decline |
| + * the app permissions. |
| + * |
| + * @param {!remoting.Error} error The failure reason. |
| + */ |
| +remoting.ApplicationInterface.prototype.signInFailed_ = function(error) {}; |
| /** |
| * Initialize the application. This is called before an OAuth token is requested |
| * and should be used for tasks such as initializing the DOM, registering event |
| - * handlers, etc. |
| + * handlers, etc. After this is called, the app is running and waiting for |
| + * user events. |
| */ |
| -remoting.Application.Delegate.prototype.init = function() {}; |
| +remoting.ApplicationInterface.prototype.initApplication_ = function() {}; |
| /** |
| - * Start the application. Once start() is called, the delegate can assume that |
| + * Start the application. Once startApplication() is called, we can assume that |
| * the user has consented to all permissions specified in the manifest. |
| * |
| - * @param {remoting.SessionConnector} connector |
| - * @param {string} token An OAuth access token. The delegate should not cache |
| + * @param {string} token An OAuth access token. The app should not cache |
| * this token, but can assume that it will remain valid during application |
| * start-up. |
| */ |
| -remoting.Application.Delegate.prototype.start = function(connector, token) {}; |
| - |
| -/** |
| - * Report an authentication error to the user. This is called in lieu of start() |
| - * if the user cannot be authenticated. |
| - * |
| - * @param {!remoting.Error} error The failure reason. |
| - */ |
| -remoting.Application.Delegate.prototype.signInFailed = function(error) {}; |
| +remoting.ApplicationInterface.prototype.startApplication_ = function(token) {}; |
| /** |
| - * @return {string} Application product name to be used in UI. |
| + * Close down the application before exiting. |
| */ |
| -remoting.Application.Delegate.prototype.getApplicationName = function() {}; |
| +remoting.ApplicationInterface.prototype.exitApplication_ = function() {}; |
| /** |
| * Called when a new session has been connected. |
| * |
| * @param {remoting.ConnectionInfo} connectionInfo |
| - * @return {void} Nothing. |
| */ |
| -remoting.Application.Delegate.prototype.handleConnected = function( |
| - connectionInfo) {}; |
| +remoting.ApplicationInterface.prototype.onConnected_ = |
| + function(connectionInfo) {}; |
| /** |
| * Called when the current session has been disconnected. |
| - * |
| - * @return {void} Nothing. |
| */ |
| -remoting.Application.Delegate.prototype.handleDisconnected = function() {}; |
| +remoting.ApplicationInterface.prototype.onDisconnected_ = function() {}; |
| /** |
| * Called when the current session's connection has failed. |
| * |
| - * @param {remoting.SessionConnector} connector |
| * @param {!remoting.Error} error |
| - * @return {void} Nothing. |
| */ |
| -remoting.Application.Delegate.prototype.handleConnectionFailed = |
| - function(connector, error) {}; |
| +remoting.ApplicationInterface.prototype.onConnectionFailed_ = |
| + function(error) {}; |
| /** |
| * Called when an error needs to be displayed to the user. |
| * |
| * @param {!remoting.Error} errorTag The error to be localized and displayed. |
| - * @return {void} Nothing. |
| - */ |
| -remoting.Application.Delegate.prototype.handleError = function(errorTag) {}; |
| - |
| -/** |
| - * Perform any application-specific cleanup before exiting. This is called in |
| - * lieu of start() if the user declines the app permissions, and will usually |
| - * be called immediately prior to exiting, although delegates should not rely |
| - * on this. |
| */ |
| -remoting.Application.Delegate.prototype.handleExit = function() {}; |
| +remoting.ApplicationInterface.prototype.onError_ = function(errorTag) {}; |
| /** @type {remoting.Application} */ |