1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5/** 6 * @fileoverview 7 * Dialog for showing the list of clients that are paired with this host. 8 */ 9 10'use strict'; 11 12/** @suppress {duplicate} */ 13var remoting = remoting || {}; 14 15/** 16 * Extract the appropriate fields from the input parameter, if present. Use the 17 * isValid() method to determine whether or not a valid paired client instance 18 * was provided. 19 * 20 * @param {Object} pairedClient The paired client, as returned by the native 21 * host instance. 22 * @constructor 23 */ 24remoting.PairedClient = function(pairedClient) { 25 if (!pairedClient || typeof(pairedClient) != 'object') { 26 return; 27 } 28 29 this.clientId = /** @type {string} */ (pairedClient['clientId']); 30 this.clientName = /** @type {string} */ (pairedClient['clientName']); 31 this.createdTime = /** @type {number} */ (pairedClient['createdTime']); 32 33 /** @type {Element} */ 34 this.tableRow = null; 35 /** @type {Element} */ 36 this.deleteButton = null; 37}; 38 39/** 40 * Create the DOM elements representing this client in the paired client 41 * manager dialog. 42 * 43 * @param {remoting.PairedClientManager} parent The paired client manager 44 * dialog containing this row. 45 * @param {Element} tbody The <tbody> element to which to append the row. 46 */ 47remoting.PairedClient.prototype.createDom = function(parent, tbody) { 48 this.tableRow = document.createElement('tr'); 49 var td = document.createElement('td'); 50 td.innerText = new Date(this.createdTime).toLocaleDateString(); 51 this.tableRow.appendChild(td); 52 td = document.createElement('td'); 53 td.innerText = this.clientName; 54 this.tableRow.appendChild(td); 55 td = document.createElement('td'); 56 this.deleteButton = document.createElement('a'); 57 this.deleteButton.href = '#'; 58 this.deleteButton.innerText = chrome.i18n.getMessage( 59 /*i18n-content*/'DELETE_PAIRED_CLIENT'); 60 this.deleteButton.id = 'delete-client-' + this.clientId; 61 this.deleteButton.addEventListener( 62 'click', 63 parent.deletePairedClient.bind(parent, this), 64 false); 65 td.appendChild(this.deleteButton); 66 this.tableRow.appendChild(td); 67 tbody.appendChild(this.tableRow); 68}; 69 70/** 71 * Show or hide the "Delete" button for this row. 72 * 73 * @param {boolean} show True to show the button; false to hide it. 74 */ 75remoting.PairedClient.prototype.showButton = function(show) { 76 this.deleteButton.hidden = !show; 77}; 78 79/** 80 * @return {boolean} True if the constructor parameter was a well-formed 81 * paired client instance. 82 */ 83remoting.PairedClient.prototype.isValid = function() { 84 return typeof(this.clientId) == 'string' && 85 typeof(this.clientName) == 'string' && 86 typeof(this.createdTime) == 'number'; 87}; 88 89/** 90 * Converts a raw object to an array of PairedClient instances. Returns null if 91 * the input object is incorrectly formatted. 92 * 93 * @param {*} pairedClients The object to convert. 94 * @return {Array.<remoting.PairedClient>} The converted result. 95 */ 96remoting.PairedClient.convertToPairedClientArray = function(pairedClients) { 97 if (!(pairedClients instanceof Array)) { 98 console.error('pairedClients is not an Array:', pairedClients); 99 return null; 100 } 101 102 var result = []; 103 for (var i = 0; i < pairedClients.length; i++) { 104 var pairedClient = new remoting.PairedClient(pairedClients[i]); 105 if (!pairedClient.isValid()) { 106 console.error('pairedClient[' + i + '] has incorrect format:', 107 /** @type {*} */(pairedClients[i])); 108 return null; 109 } 110 result.push(pairedClient); 111 } 112 return result; 113} 114 115/** 116 * @param {remoting.HostController} hostController 117 * @param {HTMLElement} listContainer HTML <div> to contain the list of paired 118 * clients. 119 * @param {HTMLElement} message HTML <div> containing the message notifying 120 * the user that clients are paired and containing the link to open the 121 * dialog. 122 * @param {HTMLElement} deleteAllButton HTML <button> inititating the "delete 123 * all" action. 124 * @param {HTMLElement} closeButton HTML <button> to close the dialog. 125 * @param {HTMLElement} noPairedClients HTML <div> containing a message shown 126 * when all clients have been deleted. 127 * @param {HTMLElement} workingSpinner HTML element containing a spinner 128 * graphic shown while a deletion is in progress. 129 * @param {HTMLElement} errorDiv HTML <div> containing an error message shown 130 * if a delete operation fails. 131 * @constructor 132 */ 133remoting.PairedClientManager = function(hostController, listContainer, message, 134 deleteAllButton, closeButton, 135 noPairedClients, workingSpinner, 136 errorDiv) { 137 /** 138 * @private 139 */ 140 this.hostController_ = hostController; 141 /** 142 * @private 143 */ 144 this.message_ = message; 145 /** 146 * @private 147 */ 148 this.deleteAllButton_ = deleteAllButton; 149 /** 150 * @private 151 */ 152 this.closeButton_ = closeButton; 153 /** 154 * @private 155 */ 156 this.noPairedClients_ = noPairedClients; 157 /** 158 * @private 159 */ 160 this.workingSpinner_ = workingSpinner; 161 /** 162 * @private 163 */ 164 this.errorDiv_ = errorDiv; 165 /** 166 * @type {Element} 167 * @private 168 */ 169 this.clientRows_ = listContainer.querySelector('tbody'); 170 /** 171 * @type {Array.<remoting.PairedClient>} 172 */ 173 this.pairedClients_ = []; 174 175 this.deleteAllButton_.addEventListener('click', 176 this.deleteAll_.bind(this), 177 false); 178}; 179 180/** 181 * Populate the dialog with the list of paired clients and show or hide the 182 * message as appropriate. 183 * 184 * @param {*} pairedClients The list of paired clients as returned by the 185 * native host component. 186 * @return {void} Nothing. 187 */ 188remoting.PairedClientManager.prototype.setPairedClients = 189 function(pairedClients) { 190 // Reset table. 191 while (this.clientRows_.lastChild) { 192 this.clientRows_.removeChild(this.clientRows_.lastChild); 193 } 194 195 this.pairedClients_ = 196 remoting.PairedClient.convertToPairedClientArray(pairedClients); 197 for (var i = 0; i < this.pairedClients_.length; ++i) { 198 var client = this.pairedClients_[i]; 199 client.createDom(this, this.clientRows_); 200 } 201 202 // Show or hide the "this computer has paired clients" message. 203 this.setWorking_(false) 204}; 205 206/** 207 * Enter or leave "working" mode. This indicates to the user that a delete 208 * operation is in progress. All dialog UI is disabled until it completes. 209 * 210 * @param {boolean} working True to enter "working" mode; false to leave it. 211 * @private 212 */ 213remoting.PairedClientManager.prototype.setWorking_ = function(working) { 214 var hasPairedClients = (this.pairedClients_.length != 0); 215 for (var i = 0; i < this.pairedClients_.length; ++i) { 216 this.pairedClients_[i].showButton(!working); 217 } 218 this.closeButton_.disabled = working; 219 this.workingSpinner_.hidden = !working; 220 this.errorDiv_.hidden = true; 221 this.message_.hidden = !hasPairedClients; 222 this.deleteAllButton_.disabled = working || !hasPairedClients; 223 this.noPairedClients_.hidden = hasPairedClients; 224}; 225 226/** 227 * Error callback for delete operations. 228 * 229 * @param {remoting.Error} error The error message. 230 * @private 231 */ 232remoting.PairedClientManager.prototype.onError_ = function(error) { 233 this.setWorking_(false); 234 l10n.localizeElementFromTag(this.errorDiv_, error); 235 this.errorDiv_.hidden = false; 236}; 237 238/** 239 * Delete a single paired client. 240 * 241 * @param {remoting.PairedClient} client The pairing to delete. 242 */ 243remoting.PairedClientManager.prototype.deletePairedClient = function(client) { 244 this.setWorking_(true); 245 this.hostController_.deletePairedClient(client.clientId, 246 this.setWorking_.bind(this, false), 247 this.onError_.bind(this)); 248 this.clientRows_.removeChild(client.tableRow); 249 for (var i = 0; i < this.pairedClients_.length; ++i) { 250 if (this.pairedClients_[i] == client) { 251 this.pairedClients_.splice(i, 1); 252 break; 253 } 254 } 255}; 256 257/** 258 * Delete all paired clients. 259 * 260 * @private 261 */ 262remoting.PairedClientManager.prototype.deleteAll_ = function() { 263 this.setWorking_(true); 264 this.hostController_.clearPairedClients( 265 this.setWorking_.bind(this, false), 266 this.onError_.bind(this)); 267 268 while (this.clientRows_.lastChild) { 269 this.clientRows_.removeChild(this.clientRows_.lastChild); 270 } 271 this.pairedClients_ = []; 272}; 273 274/** 275 * Get the id of the first paired client for testing. 276 * 277 * @private 278 * @return {string} The client id of the first paired client in the list. 279 */ 280remoting.PairedClientManager.prototype.getFirstClientIdForTesting_ = 281 function() { 282 return this.pairedClients_.length > 0 ? this.pairedClients_[0].clientId : ''; 283}; 284 285 286/** @type {remoting.PairedClientManager} */ 287remoting.pairedClientManager = null; 288