Index: remoting/webapp/me2mom/host_list.js |
diff --git a/remoting/webapp/me2mom/host_list.js b/remoting/webapp/me2mom/host_list.js |
index e09034bb8949378cd181b9b0569f2c5ed1d430ff..55f288ff66ef892a61882e691047896a6d279d26 100644 |
--- a/remoting/webapp/me2mom/host_list.js |
+++ b/remoting/webapp/me2mom/host_list.js |
@@ -16,6 +16,7 @@ var remoting = remoting || {}; |
* Create a host list consisting of the specified HTML elements, which should |
* have a common parent that contains only host-list UI as it will be hidden |
* if the host-list is empty. |
+ * |
* @constructor |
* @param {Element} table The HTML <table> to contain host-list. |
* @param {Element} errorDiv The HTML <div> to display error messages. |
@@ -35,18 +36,40 @@ remoting.HostList = function(table, errorDiv) { |
* @type {Array.<remoting.HostTableEntry>} |
* @private |
*/ |
- this.hostTableEntries_ = null; |
+ this.hostTableEntries_ = []; |
+ /** |
+ * @type {Array.<remoting.Host>} |
+ * @private |
+ */ |
+ this.hosts_ = []; |
+ /** |
+ * @type {string} |
+ * @private |
+ */ |
+ this.lastError_ = ''; |
+ |
+ // Load the cache of the last host-list, if present. |
+ var cached = /** @type {string} */ |
+ (window.localStorage.getItem(remoting.HostList.HOSTS_KEY)); |
+ if (cached) { |
+ try { |
+ this.hosts_ = /** @type {Array} */ JSON.parse(cached); |
+ } catch (err) { |
+ console.error('Invalid host list cache:', /** @type {*} */(err)); |
+ } |
+ } |
}; |
/** |
* Search the host list for a host with the specified id. |
+ * |
* @param {string} hostId The unique id of the host. |
- * @return {remoting.HostTableEntry?} The host table entry, if any. |
+ * @return {remoting.Host?} The host, if any. |
*/ |
remoting.HostList.prototype.getHostForId = function(hostId) { |
- for (var i = 0; i < this.hostTableEntries_.length; ++i) { |
- if (this.hostTableEntries_[i].host.hostId == hostId) { |
- return this.hostTableEntries_[i]; |
+ for (var i = 0; i < this.hosts_.length; ++i) { |
+ if (this.hosts_[i].hostId == hostId) { |
+ return this.hosts_[i]; |
} |
} |
return null; |
@@ -55,16 +78,18 @@ remoting.HostList.prototype.getHostForId = function(hostId) { |
/** |
* Query the Remoting Directory for the user's list of hosts. |
* |
+ * @param {function(boolean):void} onDone Callback invoked with true on success |
+ * or false on failure. |
* @return {void} Nothing. |
*/ |
-remoting.HostList.prototype.refresh = function() { |
+remoting.HostList.prototype.refresh = function(onDone) { |
/** @type {remoting.HostList} */ |
var that = this; |
- /** @param {XMLHttpRequest} xhr */ |
+ /** @param {XMLHttpRequest} xhr The response from the server. */ |
var parseHostListResponse = function(xhr) { |
- that.parseHostListResponse_(xhr); |
+ that.parseHostListResponse_(xhr, onDone); |
} |
- /** @param {string} token */ |
+ /** @param {string} token The OAuth2 token. */ |
var getHosts = function(token) { |
var headers = { 'Authorization': 'OAuth ' + token }; |
remoting.xhr.get( |
@@ -72,7 +97,7 @@ remoting.HostList.prototype.refresh = function() { |
parseHostListResponse, '', headers); |
}; |
remoting.oauth2.callWithToken(getHosts); |
-} |
+}; |
/** |
* Handle the results of the host list request. A success response will |
@@ -80,41 +105,50 @@ remoting.HostList.prototype.refresh = function() { |
* able to successfully parse it. |
* |
* @param {XMLHttpRequest} xhr The XHR object for the host list request. |
+ * @param {function(boolean):void} onDone The callback passed to |refresh|. |
* @return {void} Nothing. |
+ * @private |
*/ |
-remoting.HostList.prototype.parseHostListResponse_ = function(xhr) { |
+remoting.HostList.prototype.parseHostListResponse_ = function(xhr, onDone) { |
+ this.hosts_ = []; |
+ this.lastError_ = ''; |
try { |
if (xhr.status == 200) { |
var parsed_response = |
/** @type {{data: {items: Array}}} */ JSON.parse(xhr.responseText); |
if (parsed_response.data && parsed_response.data.items) { |
- this.setHosts_(parsed_response.data.items); |
+ this.hosts_ = parsed_response.data.items; |
} |
} else { |
// Some other error. |
console.error('Bad status on host list query: ', xhr); |
- // For most errors in the 4xx range, tell the user to re-authorize us. |
if (xhr.status == 403) { |
// The user's account is not enabled for Me2Me, so fail silently. |
- } else if (xhr.status >= 400 && xhr.status <= 499) { |
- this.showError_(remoting.Error.GENERIC); |
+ } else if (xhr.status >= 400 && xhr.status < 500) { |
+ // For other errors, tell the user to re-authorize us. |
+ this.lastError_ = remoting.Error.GENERIC; |
+ } else { |
+ this.lastError_ = remoting.Error.UNEXPECTED; |
} |
} |
} catch (er) { |
var typed_er = /** @type {Object} */ (er); |
console.error('Error processing response: ', xhr, typed_er); |
+ this.lastError_ = remoting.Error.UNEXPECTED; |
} |
-} |
+ window.localStorage.setItem(remoting.HostList.HOSTS_KEY, |
+ JSON.stringify(this.hosts_)); |
+ onDone(this.lastError_ == ''); |
+}; |
/** |
- * Refresh the host list with up-to-date details. |
- * @param {Array.<remoting.Host>} hosts The new host list. |
+ * Display the list of hosts or error condition. |
+ * |
* @return {void} Nothing. |
- * @private |
*/ |
-remoting.HostList.prototype.setHosts_ = function(hosts) { |
+remoting.HostList.prototype.display = function() { |
this.table_.innerHTML = ''; |
- this.showError_(null); |
+ this.errorDiv_.innerText = ''; |
this.hostTableEntries_ = []; |
/** |
@@ -130,9 +164,9 @@ remoting.HostList.prototype.setHosts_ = function(hosts) { |
*/ |
var onDelete = function(hostTableEntry) { that.deleteHost_(hostTableEntry); } |
- for (var i = 0; i < hosts.length; ++i) { |
+ for (var i = 0; i < this.hosts_.length; ++i) { |
/** @type {remoting.Host} */ |
- var host = hosts[i]; |
+ var host = this.hosts_[i]; |
// Validate the entry to make sure it has all the fields we expect. |
if (host.hostName && host.hostId && host.status && host.jabberId && |
host.publicKey) { |
@@ -143,28 +177,16 @@ remoting.HostList.prototype.setHosts_ = function(hosts) { |
} |
} |
- this.showOrHide_(this.hostTableEntries_.length != 0); |
-}; |
- |
-/** |
- * Display a localized error message. |
- * @param {remoting.Error?} errorTag The error to display, or NULL to clear any |
- * previous error. |
- * @return {void} Nothing. |
- */ |
-remoting.HostList.prototype.showError_ = function(errorTag) { |
- this.table_.innerHTML = ''; |
- if (errorTag) { |
- l10n.localizeElementFromTag(this.errorDiv_, |
- /** @type {string} */ (errorTag)); |
- this.showOrHide_(true); |
- } else { |
- this.errorDiv_.innerText = ''; |
+ if (this.lastError_ != '') { |
+ l10n.localizeElementFromTag(this.errorDiv_, this.lastError_); |
} |
+ |
+ this.showOrHide_(this.hosts_.length != 0 || this.lastError_ != ''); |
}; |
/** |
* Show or hide the host-list UI. |
+ * |
* @param {boolean} show True to show the UI, or false to hide it. |
* @return {void} Nothing. |
* @private |
@@ -193,7 +215,7 @@ remoting.HostList.prototype.deleteHost_ = function(hostTableEntry) { |
this.hostTableEntries_.splice(index, 1); |
} |
- /** @param {string} token */ |
+ /** @param {string} token The OAuth2 token. */ |
var deleteHost = function(token) { |
var headers = { 'Authorization': 'OAuth ' + token }; |
remoting.xhr.remove( |
@@ -240,5 +262,10 @@ remoting.HostList.prototype.renameHost_ = function(hostTableEntry) { |
*/ |
remoting.HostList.COLLAPSED_ = 'collapsed'; |
+/** |
+ * Key name under which Me2Me hosts are cached. |
+ */ |
+remoting.HostList.HOSTS_KEY = 'me2me-cached-hosts'; |
+ |
/** @type {remoting.HostList} */ |
remoting.hostList = null; |