• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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