OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview | 6 * @fileoverview |
7 * Class representing the host-list portion of the home screen UI. | 7 * Class representing the host-list portion of the home screen UI. |
8 */ | 8 */ |
9 | 9 |
10 'use strict'; | 10 'use strict'; |
11 | 11 |
12 /** @suppress {duplicate} */ | 12 /** @suppress {duplicate} */ |
13 var remoting = remoting || {}; | 13 var remoting = remoting || {}; |
14 | 14 |
15 /** | 15 /** |
16 * Create a host list consisting of the specified HTML elements, which should | 16 * Create a host list consisting of the specified HTML elements, which should |
17 * have a common parent that contains only host-list UI as it will be hidden | 17 * have a common parent that contains only host-list UI as it will be hidden |
18 * if the host-list is empty. | 18 * if the host-list is empty. |
| 19 * |
19 * @constructor | 20 * @constructor |
20 * @param {Element} table The HTML <table> to contain host-list. | 21 * @param {Element} table The HTML <table> to contain host-list. |
21 * @param {Element} errorDiv The HTML <div> to display error messages. | 22 * @param {Element} errorDiv The HTML <div> to display error messages. |
22 */ | 23 */ |
23 remoting.HostList = function(table, errorDiv) { | 24 remoting.HostList = function(table, errorDiv) { |
24 /** | 25 /** |
25 * @type {Element} | 26 * @type {Element} |
26 * @private | 27 * @private |
27 */ | 28 */ |
28 this.table_ = table; | 29 this.table_ = table; |
29 /** | 30 /** |
30 * @type {Element} | 31 * @type {Element} |
31 * @private | 32 * @private |
32 */ | 33 */ |
33 this.errorDiv_ = errorDiv; | 34 this.errorDiv_ = errorDiv; |
34 /** | 35 /** |
35 * @type {Array.<remoting.HostTableEntry>} | 36 * @type {Array.<remoting.HostTableEntry>} |
36 * @private | 37 * @private |
37 */ | 38 */ |
38 this.hostTableEntries_ = null; | 39 this.hostTableEntries_ = []; |
| 40 /** |
| 41 * @type {Array.<remoting.Host>} |
| 42 * @private |
| 43 */ |
| 44 this.hosts_ = []; |
| 45 /** |
| 46 * @type {string} |
| 47 * @private |
| 48 */ |
| 49 this.lastError_ = ''; |
| 50 |
| 51 // Load the cache of the last host-list, if present. |
| 52 var cached = /** @type {string} */ |
| 53 (window.localStorage.getItem(remoting.HostList.HOSTS_KEY)); |
| 54 if (cached) { |
| 55 try { |
| 56 this.hosts_ = /** @type {Array} */ JSON.parse(cached); |
| 57 } catch (err) { |
| 58 console.error('Invalid host list cache:', /** @type {*} */(err)); |
| 59 } |
| 60 } |
39 }; | 61 }; |
40 | 62 |
41 /** | 63 /** |
42 * Search the host list for a host with the specified id. | 64 * Search the host list for a host with the specified id. |
| 65 * |
43 * @param {string} hostId The unique id of the host. | 66 * @param {string} hostId The unique id of the host. |
44 * @return {remoting.HostTableEntry?} The host table entry, if any. | 67 * @return {remoting.Host?} The host, if any. |
45 */ | 68 */ |
46 remoting.HostList.prototype.getHostForId = function(hostId) { | 69 remoting.HostList.prototype.getHostForId = function(hostId) { |
47 for (var i = 0; i < this.hostTableEntries_.length; ++i) { | 70 for (var i = 0; i < this.hosts_.length; ++i) { |
48 if (this.hostTableEntries_[i].host.hostId == hostId) { | 71 if (this.hosts_[i].hostId == hostId) { |
49 return this.hostTableEntries_[i]; | 72 return this.hosts_[i]; |
50 } | 73 } |
51 } | 74 } |
52 return null; | 75 return null; |
53 }; | 76 }; |
54 | 77 |
55 /** | 78 /** |
56 * Query the Remoting Directory for the user's list of hosts. | 79 * Query the Remoting Directory for the user's list of hosts. |
57 * | 80 * |
| 81 * @param {function(boolean):void} onDone Callback invoked with true on success |
| 82 * or false on failure. |
58 * @return {void} Nothing. | 83 * @return {void} Nothing. |
59 */ | 84 */ |
60 remoting.HostList.prototype.refresh = function() { | 85 remoting.HostList.prototype.refresh = function(onDone) { |
61 /** @type {remoting.HostList} */ | 86 /** @type {remoting.HostList} */ |
62 var that = this; | 87 var that = this; |
63 /** @param {XMLHttpRequest} xhr */ | 88 /** @param {XMLHttpRequest} xhr The response from the server. */ |
64 var parseHostListResponse = function(xhr) { | 89 var parseHostListResponse = function(xhr) { |
65 that.parseHostListResponse_(xhr); | 90 that.parseHostListResponse_(xhr, onDone); |
66 } | 91 } |
67 /** @param {string} token */ | 92 /** @param {string} token The OAuth2 token. */ |
68 var getHosts = function(token) { | 93 var getHosts = function(token) { |
69 var headers = { 'Authorization': 'OAuth ' + token }; | 94 var headers = { 'Authorization': 'OAuth ' + token }; |
70 remoting.xhr.get( | 95 remoting.xhr.get( |
71 'https://www.googleapis.com/chromoting/v1/@me/hosts', | 96 'https://www.googleapis.com/chromoting/v1/@me/hosts', |
72 parseHostListResponse, '', headers); | 97 parseHostListResponse, '', headers); |
73 }; | 98 }; |
74 remoting.oauth2.callWithToken(getHosts); | 99 remoting.oauth2.callWithToken(getHosts); |
75 } | 100 }; |
76 | 101 |
77 /** | 102 /** |
78 * Handle the results of the host list request. A success response will | 103 * Handle the results of the host list request. A success response will |
79 * include a JSON-encoded list of host descriptions, which we display if we're | 104 * include a JSON-encoded list of host descriptions, which we display if we're |
80 * able to successfully parse it. | 105 * able to successfully parse it. |
81 * | 106 * |
82 * @param {XMLHttpRequest} xhr The XHR object for the host list request. | 107 * @param {XMLHttpRequest} xhr The XHR object for the host list request. |
| 108 * @param {function(boolean):void} onDone The callback passed to |refresh|. |
83 * @return {void} Nothing. | 109 * @return {void} Nothing. |
| 110 * @private |
84 */ | 111 */ |
85 remoting.HostList.prototype.parseHostListResponse_ = function(xhr) { | 112 remoting.HostList.prototype.parseHostListResponse_ = function(xhr, onDone) { |
| 113 this.hosts_ = []; |
| 114 this.lastError_ = ''; |
86 try { | 115 try { |
87 if (xhr.status == 200) { | 116 if (xhr.status == 200) { |
88 var parsed_response = | 117 var parsed_response = |
89 /** @type {{data: {items: Array}}} */ JSON.parse(xhr.responseText); | 118 /** @type {{data: {items: Array}}} */ JSON.parse(xhr.responseText); |
90 if (parsed_response.data && parsed_response.data.items) { | 119 if (parsed_response.data && parsed_response.data.items) { |
91 this.setHosts_(parsed_response.data.items); | 120 this.hosts_ = parsed_response.data.items; |
92 } | 121 } |
93 } else { | 122 } else { |
94 // Some other error. | 123 // Some other error. |
95 console.error('Bad status on host list query: ', xhr); | 124 console.error('Bad status on host list query: ', xhr); |
96 // For most errors in the 4xx range, tell the user to re-authorize us. | |
97 if (xhr.status == 403) { | 125 if (xhr.status == 403) { |
98 // The user's account is not enabled for Me2Me, so fail silently. | 126 // The user's account is not enabled for Me2Me, so fail silently. |
99 } else if (xhr.status >= 400 && xhr.status <= 499) { | 127 } else if (xhr.status >= 400 && xhr.status < 500) { |
100 this.showError_(remoting.Error.GENERIC); | 128 // For other errors, tell the user to re-authorize us. |
| 129 this.lastError_ = remoting.Error.GENERIC; |
| 130 } else { |
| 131 this.lastError_ = remoting.Error.UNEXPECTED; |
101 } | 132 } |
102 } | 133 } |
103 } catch (er) { | 134 } catch (er) { |
104 var typed_er = /** @type {Object} */ (er); | 135 var typed_er = /** @type {Object} */ (er); |
105 console.error('Error processing response: ', xhr, typed_er); | 136 console.error('Error processing response: ', xhr, typed_er); |
| 137 this.lastError_ = remoting.Error.UNEXPECTED; |
106 } | 138 } |
107 } | 139 window.localStorage.setItem(remoting.HostList.HOSTS_KEY, |
| 140 JSON.stringify(this.hosts_)); |
| 141 onDone(this.lastError_ == ''); |
| 142 }; |
108 | 143 |
109 /** | 144 /** |
110 * Refresh the host list with up-to-date details. | 145 * Display the list of hosts or error condition. |
111 * @param {Array.<remoting.Host>} hosts The new host list. | 146 * |
112 * @return {void} Nothing. | 147 * @return {void} Nothing. |
113 * @private | |
114 */ | 148 */ |
115 remoting.HostList.prototype.setHosts_ = function(hosts) { | 149 remoting.HostList.prototype.display = function() { |
116 this.table_.innerHTML = ''; | 150 this.table_.innerHTML = ''; |
117 this.showError_(null); | 151 this.errorDiv_.innerText = ''; |
118 this.hostTableEntries_ = []; | 152 this.hostTableEntries_ = []; |
119 | 153 |
120 /** | 154 /** |
121 * @type {remoting.HostList} | 155 * @type {remoting.HostList} |
122 */ | 156 */ |
123 var that = this; | 157 var that = this; |
124 /** | 158 /** |
125 * @param {remoting.HostTableEntry} hostTableEntry The entry being renamed. | 159 * @param {remoting.HostTableEntry} hostTableEntry The entry being renamed. |
126 */ | 160 */ |
127 var onRename = function(hostTableEntry) { that.renameHost_(hostTableEntry); } | 161 var onRename = function(hostTableEntry) { that.renameHost_(hostTableEntry); } |
128 /** | 162 /** |
129 * @param {remoting.HostTableEntry} hostTableEntry The entry beign deleted. | 163 * @param {remoting.HostTableEntry} hostTableEntry The entry beign deleted. |
130 */ | 164 */ |
131 var onDelete = function(hostTableEntry) { that.deleteHost_(hostTableEntry); } | 165 var onDelete = function(hostTableEntry) { that.deleteHost_(hostTableEntry); } |
132 | 166 |
133 for (var i = 0; i < hosts.length; ++i) { | 167 for (var i = 0; i < this.hosts_.length; ++i) { |
134 /** @type {remoting.Host} */ | 168 /** @type {remoting.Host} */ |
135 var host = hosts[i]; | 169 var host = this.hosts_[i]; |
136 // Validate the entry to make sure it has all the fields we expect. | 170 // Validate the entry to make sure it has all the fields we expect. |
137 if (host.hostName && host.hostId && host.status && host.jabberId && | 171 if (host.hostName && host.hostId && host.status && host.jabberId && |
138 host.publicKey) { | 172 host.publicKey) { |
139 var hostTableEntry = new remoting.HostTableEntry(); | 173 var hostTableEntry = new remoting.HostTableEntry(); |
140 hostTableEntry.init(host, onRename, onDelete); | 174 hostTableEntry.init(host, onRename, onDelete); |
141 this.hostTableEntries_[i] = hostTableEntry; | 175 this.hostTableEntries_[i] = hostTableEntry; |
142 this.table_.appendChild(hostTableEntry.tableRow); | 176 this.table_.appendChild(hostTableEntry.tableRow); |
143 } | 177 } |
144 } | 178 } |
145 | 179 |
146 this.showOrHide_(this.hostTableEntries_.length != 0); | 180 if (this.lastError_ != '') { |
147 }; | 181 l10n.localizeElementFromTag(this.errorDiv_, this.lastError_); |
| 182 } |
148 | 183 |
149 /** | 184 this.showOrHide_(this.hosts_.length != 0 || this.lastError_ != ''); |
150 * Display a localized error message. | |
151 * @param {remoting.Error?} errorTag The error to display, or NULL to clear any | |
152 * previous error. | |
153 * @return {void} Nothing. | |
154 */ | |
155 remoting.HostList.prototype.showError_ = function(errorTag) { | |
156 this.table_.innerHTML = ''; | |
157 if (errorTag) { | |
158 l10n.localizeElementFromTag(this.errorDiv_, | |
159 /** @type {string} */ (errorTag)); | |
160 this.showOrHide_(true); | |
161 } else { | |
162 this.errorDiv_.innerText = ''; | |
163 } | |
164 }; | 185 }; |
165 | 186 |
166 /** | 187 /** |
167 * Show or hide the host-list UI. | 188 * Show or hide the host-list UI. |
| 189 * |
168 * @param {boolean} show True to show the UI, or false to hide it. | 190 * @param {boolean} show True to show the UI, or false to hide it. |
169 * @return {void} Nothing. | 191 * @return {void} Nothing. |
170 * @private | 192 * @private |
171 */ | 193 */ |
172 remoting.HostList.prototype.showOrHide_ = function(show) { | 194 remoting.HostList.prototype.showOrHide_ = function(show) { |
173 var parent = /** @type {Element} */ (this.table_.parentNode); | 195 var parent = /** @type {Element} */ (this.table_.parentNode); |
174 parent.hidden = !show; | 196 parent.hidden = !show; |
175 if (show) { | 197 if (show) { |
176 parent.style.height = parent.scrollHeight + 'px'; | 198 parent.style.height = parent.scrollHeight + 'px'; |
177 removeClass(parent, remoting.HostList.COLLAPSED_); | 199 removeClass(parent, remoting.HostList.COLLAPSED_); |
178 } else { | 200 } else { |
179 addClass(parent, remoting.HostList.COLLAPSED_); | 201 addClass(parent, remoting.HostList.COLLAPSED_); |
180 } | 202 } |
181 }; | 203 }; |
182 | 204 |
183 /** | 205 /** |
184 * Remove a host from the list, and deregister it. | 206 * Remove a host from the list, and deregister it. |
185 * @param {remoting.HostTableEntry} hostTableEntry The host to be removed. | 207 * @param {remoting.HostTableEntry} hostTableEntry The host to be removed. |
186 * @return {void} Nothing. | 208 * @return {void} Nothing. |
187 * @private | 209 * @private |
188 */ | 210 */ |
189 remoting.HostList.prototype.deleteHost_ = function(hostTableEntry) { | 211 remoting.HostList.prototype.deleteHost_ = function(hostTableEntry) { |
190 this.table_.removeChild(hostTableEntry.tableRow); | 212 this.table_.removeChild(hostTableEntry.tableRow); |
191 var index = this.hostTableEntries_.indexOf(hostTableEntry); | 213 var index = this.hostTableEntries_.indexOf(hostTableEntry); |
192 if (index != -1) { | 214 if (index != -1) { |
193 this.hostTableEntries_.splice(index, 1); | 215 this.hostTableEntries_.splice(index, 1); |
194 } | 216 } |
195 | 217 |
196 /** @param {string} token */ | 218 /** @param {string} token The OAuth2 token. */ |
197 var deleteHost = function(token) { | 219 var deleteHost = function(token) { |
198 var headers = { 'Authorization': 'OAuth ' + token }; | 220 var headers = { 'Authorization': 'OAuth ' + token }; |
199 remoting.xhr.remove( | 221 remoting.xhr.remove( |
200 'https://www.googleapis.com/chromoting/v1/@me/hosts/' + | 222 'https://www.googleapis.com/chromoting/v1/@me/hosts/' + |
201 hostTableEntry.host.hostId, | 223 hostTableEntry.host.hostId, |
202 function() {}, '', headers); | 224 function() {}, '', headers); |
203 } | 225 } |
204 remoting.oauth2.callWithToken(deleteHost); | 226 remoting.oauth2.callWithToken(deleteHost); |
205 | 227 |
206 this.showOrHide_(this.hostTableEntries_.length != 0); | 228 this.showOrHide_(this.hostTableEntries_.length != 0); |
(...skipping 26 matching lines...) Expand all Loading... |
233 } | 255 } |
234 remoting.oauth2.callWithToken(renameHost); | 256 remoting.oauth2.callWithToken(renameHost); |
235 }; | 257 }; |
236 | 258 |
237 /** | 259 /** |
238 * Class name for the host list when it is collapsed. | 260 * Class name for the host list when it is collapsed. |
239 * @private | 261 * @private |
240 */ | 262 */ |
241 remoting.HostList.COLLAPSED_ = 'collapsed'; | 263 remoting.HostList.COLLAPSED_ = 'collapsed'; |
242 | 264 |
| 265 /** |
| 266 * Key name under which Me2Me hosts are cached. |
| 267 */ |
| 268 remoting.HostList.HOSTS_KEY = 'me2me-cached-hosts'; |
| 269 |
243 /** @type {remoting.HostList} */ | 270 /** @type {remoting.HostList} */ |
244 remoting.hostList = null; | 271 remoting.hostList = null; |
OLD | NEW |