// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @fileoverview * Dialog for showing the list of clients that are paired with this host. */ 'use strict'; /** @suppress {duplicate} */ var remoting = remoting || {}; /** * Extract the appropriate fields from the input parameter, if present. Use the * isValid() method to determine whether or not a valid paired client instance * was provided. * * @param {Object} pairedClient The paired client, as returned by the native * host instance. * @constructor */ remoting.PairedClient = function(pairedClient) { if (!pairedClient || typeof(pairedClient) != 'object') { return; } this.clientId = /** @type {string} */ (pairedClient['clientId']); this.clientName = /** @type {string} */ (pairedClient['clientName']); this.createdTime = /** @type {number} */ (pairedClient['createdTime']); /** @type {Element} */ this.tableRow = null; /** @type {Element} */ this.deleteButton = null; }; /** * Create the DOM elements representing this client in the paired client * manager dialog. * * @param {remoting.PairedClientManager} parent The paired client manager * dialog containing this row. * @param {Element} tbody The <tbody> element to which to append the row. */ remoting.PairedClient.prototype.createDom = function(parent, tbody) { this.tableRow = document.createElement('tr'); var td = document.createElement('td'); td.innerText = new Date(this.createdTime).toLocaleDateString(); this.tableRow.appendChild(td); td = document.createElement('td'); td.innerText = this.clientName; this.tableRow.appendChild(td); td = document.createElement('td'); this.deleteButton = document.createElement('a'); this.deleteButton.href = '#'; this.deleteButton.innerText = chrome.i18n.getMessage( /*i18n-content*/'DELETE_PAIRED_CLIENT'); this.deleteButton.id = 'delete-client-' + this.clientId; this.deleteButton.addEventListener( 'click', parent.deletePairedClient.bind(parent, this), false); td.appendChild(this.deleteButton); this.tableRow.appendChild(td); tbody.appendChild(this.tableRow); }; /** * Show or hide the "Delete" button for this row. * * @param {boolean} show True to show the button; false to hide it. */ remoting.PairedClient.prototype.showButton = function(show) { this.deleteButton.hidden = !show; }; /** * @return {boolean} True if the constructor parameter was a well-formed * paired client instance. */ remoting.PairedClient.prototype.isValid = function() { return typeof(this.clientId) == 'string' && typeof(this.clientName) == 'string' && typeof(this.createdTime) == 'number'; }; /** * Converts a raw object to an array of PairedClient instances. Returns null if * the input object is incorrectly formatted. * * @param {*} pairedClients The object to convert. * @return {Array.<remoting.PairedClient>} The converted result. */ remoting.PairedClient.convertToPairedClientArray = function(pairedClients) { if (!(pairedClients instanceof Array)) { console.error('pairedClients is not an Array:', pairedClients); return null; } var result = []; for (var i = 0; i < pairedClients.length; i++) { var pairedClient = new remoting.PairedClient(pairedClients[i]); if (!pairedClient.isValid()) { console.error('pairedClient[' + i + '] has incorrect format:', /** @type {*} */(pairedClients[i])); return null; } result.push(pairedClient); } return result; } /** * @param {remoting.HostController} hostController * @param {HTMLElement} listContainer HTML <div> to contain the list of paired * clients. * @param {HTMLElement} message HTML <div> containing the message notifying * the user that clients are paired and containing the link to open the * dialog. * @param {HTMLElement} deleteAllButton HTML <button> inititating the "delete * all" action. * @param {HTMLElement} closeButton HTML <button> to close the dialog. * @param {HTMLElement} noPairedClients HTML <div> containing a message shown * when all clients have been deleted. * @param {HTMLElement} workingSpinner HTML element containing a spinner * graphic shown while a deletion is in progress. * @param {HTMLElement} errorDiv HTML <div> containing an error message shown * if a delete operation fails. * @constructor */ remoting.PairedClientManager = function(hostController, listContainer, message, deleteAllButton, closeButton, noPairedClients, workingSpinner, errorDiv) { /** * @private */ this.hostController_ = hostController; /** * @private */ this.message_ = message; /** * @private */ this.deleteAllButton_ = deleteAllButton; /** * @private */ this.closeButton_ = closeButton; /** * @private */ this.noPairedClients_ = noPairedClients; /** * @private */ this.workingSpinner_ = workingSpinner; /** * @private */ this.errorDiv_ = errorDiv; /** * @type {Element} * @private */ this.clientRows_ = listContainer.querySelector('tbody'); /** * @type {Array.<remoting.PairedClient>} */ this.pairedClients_ = []; this.deleteAllButton_.addEventListener('click', this.deleteAll_.bind(this), false); }; /** * Populate the dialog with the list of paired clients and show or hide the * message as appropriate. * * @param {*} pairedClients The list of paired clients as returned by the * native host component. * @return {void} Nothing. */ remoting.PairedClientManager.prototype.setPairedClients = function(pairedClients) { // Reset table. while (this.clientRows_.lastChild) { this.clientRows_.removeChild(this.clientRows_.lastChild); } this.pairedClients_ = remoting.PairedClient.convertToPairedClientArray(pairedClients); for (var i = 0; i < this.pairedClients_.length; ++i) { var client = this.pairedClients_[i]; client.createDom(this, this.clientRows_); } // Show or hide the "this computer has paired clients" message. this.setWorking_(false) }; /** * Enter or leave "working" mode. This indicates to the user that a delete * operation is in progress. All dialog UI is disabled until it completes. * * @param {boolean} working True to enter "working" mode; false to leave it. * @private */ remoting.PairedClientManager.prototype.setWorking_ = function(working) { var hasPairedClients = (this.pairedClients_.length != 0); for (var i = 0; i < this.pairedClients_.length; ++i) { this.pairedClients_[i].showButton(!working); } this.closeButton_.disabled = working; this.workingSpinner_.hidden = !working; this.errorDiv_.hidden = true; this.message_.hidden = !hasPairedClients; this.deleteAllButton_.disabled = working || !hasPairedClients; this.noPairedClients_.hidden = hasPairedClients; }; /** * Error callback for delete operations. * * @param {remoting.Error} error The error message. * @private */ remoting.PairedClientManager.prototype.onError_ = function(error) { this.setWorking_(false); l10n.localizeElementFromTag(this.errorDiv_, error); this.errorDiv_.hidden = false; }; /** * Delete a single paired client. * * @param {remoting.PairedClient} client The pairing to delete. */ remoting.PairedClientManager.prototype.deletePairedClient = function(client) { this.setWorking_(true); this.hostController_.deletePairedClient(client.clientId, this.setWorking_.bind(this, false), this.onError_.bind(this)); this.clientRows_.removeChild(client.tableRow); for (var i = 0; i < this.pairedClients_.length; ++i) { if (this.pairedClients_[i] == client) { this.pairedClients_.splice(i, 1); break; } } }; /** * Delete all paired clients. * * @private */ remoting.PairedClientManager.prototype.deleteAll_ = function() { this.setWorking_(true); this.hostController_.clearPairedClients( this.setWorking_.bind(this, false), this.onError_.bind(this)); while (this.clientRows_.lastChild) { this.clientRows_.removeChild(this.clientRows_.lastChild); } this.pairedClients_ = []; }; /** * Get the id of the first paired client for testing. * * @private * @return {string} The client id of the first paired client in the list. */ remoting.PairedClientManager.prototype.getFirstClientIdForTesting_ = function() { return this.pairedClients_.length > 0 ? this.pairedClients_[0].clientId : ''; }; /** @type {remoting.PairedClientManager} */ remoting.pairedClientManager = null;