| // Copyright (c) 2012 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. |
| |
| var localStrings = new LocalStrings(); |
| |
| cr.define('diag', function() { |
| /** |
| * Encapsulated handling of the diagnostics page. |
| */ |
| function DiagPage() {} |
| |
| cr.addSingletonGetter(DiagPage); |
| |
| /* |
| * Remove all children nodes for an element. |
| * @param {element} parent of the elements to be removed. |
| */ |
| function removeChildren(element) { |
| element.textContent = ''; |
| } |
| |
| /** |
| * List of network adapter types. |
| */ |
| DiagPage.AdapterType = [ |
| {adapter: 'wifi', name: localStrings.getString('wifi'), kind: 'wifi'}, |
| {adapter: 'ethernet', name: localStrings.getString('ethernet1'), |
| kind: 'ethernet'}, |
| {adapter: 'ethernet2', name: localStrings.getString('ethernet2'), |
| kind: 'ethernet'}, |
| {adapter: 'cellular', name: localStrings.getString('3g'), kind: '3g'}, |
| ]; |
| |
| /** |
| * List of network adapter status. |
| * The numeric value assigned to each status reflects how healthy the network |
| * adapter is. |
| * |
| * @enum {int} |
| */ |
| DiagPage.AdapterStatus = { |
| NOT_FOUND: 0, |
| DISABLED: 1, |
| NO_IP: 2, |
| VALID_IP: 3 |
| }; |
| |
| /** |
| * List of ping test status. |
| * The numeric value assigned to each status reflects how much progress has |
| * been made for the ping test. |
| * |
| * @enum {int} |
| */ |
| DiagPage.PingTestStatus = { |
| NOT_STARTED: 0, |
| IN_PROGRESS: 1, |
| FAILED: 2, |
| SUCCEEDED: 3 |
| }; |
| |
| /** |
| * Image elements for icons. |
| */ |
| DiagPage.FailIconElement = document.createElement('img'); |
| DiagPage.TickIconElement = document.createElement('img'); |
| DiagPage.FailIconElement.setAttribute('src', 'chrome://diagnostics/fail.png'); |
| DiagPage.TickIconElement.setAttribute('src', 'chrome://diagnostics/tick.png'); |
| |
| DiagPage.prototype = { |
| /** |
| * Perform initial setup. |
| */ |
| initialize: function() { |
| // Reset the diag page state. |
| this.reset_(); |
| |
| // Register event handlers. |
| $('connectivity-refresh').addEventListener('click', function() { |
| if (!this.getNetifStatusInProgress_) |
| this.reset_(); |
| }.bind(this)); |
| }, |
| |
| /** |
| * Resets the diag page state. |
| */ |
| reset_: function() { |
| // Initialize member variables. |
| this.activeAdapter_ = -1; |
| this.adapterStatus_ = new Array(); |
| if (!this.pingTestStatus_ || |
| this.pingTestStatus_ != DiagPage.PingTestStatus.IN_PROGRESS) { |
| this.pingTestStatus_ = DiagPage.PingTestStatus.NOT_STARTED; |
| } |
| |
| // Initialize the UI with "loading" message. |
| $('loading').hidden = false; |
| $('choose-adapter').hidden = true; |
| removeChildren($('adapter-selection')); |
| removeChildren($('connectivity-status')); |
| |
| // Call into Chrome to get network interfaces status. |
| chrome.send('getNetworkInterfaces'); |
| this.getNetifStatusInProgress_ = true; |
| }, |
| |
| /** |
| * Updates the connectivity status with the device information. |
| * @param {Object} deviceStatus Dictionary of network adapter status. |
| */ |
| setDeviceStatus: function(deviceStatus) { |
| // Hide the "loading" message and show the "choose-adapter" message. |
| $('loading').hidden = true; |
| $('choose-adapter').hidden = false; |
| |
| // Reset all adapters status. |
| var adapterLookup = {}; |
| for (var i = 0; i < DiagPage.AdapterType.length; i++) { |
| this.adapterStatus_[i] = DiagPage.AdapterStatus.NOT_FOUND; |
| adapterLookup[DiagPage.AdapterType[i].adapter] = i; |
| } |
| |
| // Update adapter status from data. |
| var foundValidIp = false; |
| for (var devicePath in deviceStatus) { |
| var device = deviceStatus[devicePath]; |
| var type = device['Type']; |
| var idx = adapterLookup[type]; |
| if (idx == null) { |
| console.warning('Unexpected adapter type: ' + type); |
| continue; |
| } |
| |
| // Special case for multiple ethernet adapters. |
| if (type == 'ethernet' && |
| this.adapterStatus_[idx] != DiagPage.AdapterStatus.NOT_FOUND) { |
| type = 'ethernet2'; |
| idx = adapterLookup[type]; |
| } |
| |
| this.adapterStatus_[idx] = device['Powered'] == true ? |
| DiagPage.AdapterStatus.NO_IP : DiagPage.AdapterStatus.DISABLED; |
| var ipconfigs = device['ipconfigs']; |
| for (var ipconfigPath in ipconfigs) { |
| var ipconfig = ipconfigs[ipconfigPath]; |
| if (ipconfig['Address']) { |
| this.adapterStatus_[idx] = DiagPage.AdapterStatus.VALID_IP; |
| foundValidIp = true; |
| } |
| } |
| } |
| |
| // If we have valid IP, start ping test. |
| if (foundValidIp && |
| this.pingTestStatus_ == DiagPage.PingTestStatus.NOT_STARTED) { |
| this.pingTestStatus_ == DiagPage.PingTestStatus.IN_PROGRESS; |
| chrome.send('testICMP', [String('8.8.8.8')]); |
| } |
| |
| // Update UI |
| this.updateAdapterSelection_(); |
| this.updateConnectivityStatus_(); |
| |
| // Clear the getNetifStatusInProgress flag. |
| this.getNetifStatusInProgress_ = false; |
| }, |
| |
| /** |
| * Updates the ICMP connectivity status. |
| * @param {Object} testICMPStatus Dictionary of ICMP connectivity status. |
| */ |
| setTestICMPStatus_: function(testICMPStatus) { |
| // Update the ping test state. |
| for (var prop in testICMPStatus) { |
| var status = testICMPStatus[prop]; |
| if (status.sent && status.recvd && status.sent == status.recvd) |
| this.pingTestStatus_ = DiagPage.PingTestStatus.SUCCEEDED; |
| else |
| this.pingTestStatus_ = DiagPage.PingTestStatus.FAILED; |
| break; |
| } |
| |
| // Update UI |
| this.updateConnectivityStatus_(); |
| }, |
| |
| /** |
| * Gets the HTML radio input element id for a network adapter. |
| * @private |
| */ |
| getAdapterElementId_: function(adapter) { |
| return 'adapter-' + DiagPage.AdapterType[adapter].adapter; |
| }, |
| |
| /** |
| * Gets the most active adapter based on their status. |
| * @private |
| */ |
| getActiveAdapter_: function() { |
| var activeAdapter = -1; |
| var activeAdapterStatus = DiagPage.AdapterStatus.NOT_FOUND; |
| for (var i = 0; i < DiagPage.AdapterType.length; i++) { |
| var status = this.adapterStatus_[i]; |
| if (status == DiagPage.AdapterStatus.NOT_FOUND) |
| continue; |
| if (activeAdapter == -1 || status > activeAdapterStatus) { |
| activeAdapter = i; |
| activeAdapterStatus = status; |
| } |
| } |
| return activeAdapter; |
| }, |
| |
| /** |
| * Update the adapter selection section. |
| * @private |
| */ |
| updateAdapterSelection_: function() { |
| // Determine active adapter. |
| if (this.activeAdapter_ == -1) |
| this.activeAdapter_ = this.getActiveAdapter_(); |
| // Clear adapter selection section. |
| var adapterSelectionElement = $('adapter-selection'); |
| removeChildren(adapterSelectionElement); |
| // Create HTML radio input elements. |
| for (var i = 0; i < DiagPage.AdapterType.length; i++) { |
| if (this.adapterStatus_[i] == DiagPage.AdapterStatus.NOT_FOUND) |
| continue; |
| var radioElement = document.createElement('input'); |
| var elementId = this.getAdapterElementId_(i); |
| radioElement.setAttribute('type', 'radio'); |
| radioElement.setAttribute('name', 'adapter'); |
| radioElement.setAttribute('id', elementId); |
| if (i == this.activeAdapter_) |
| radioElement.setAttribute('checked', 'true'); |
| radioElement.onclick = function(adapter) { |
| this.activeAdapter_ = adapter; |
| this.updateConnectivityStatus_(); |
| }.bind(this, i); |
| var labelElement = document.createElement('label'); |
| labelElement.setAttribute('for', elementId); |
| labelElement.appendChild(radioElement); |
| labelElement.appendChild( |
| document.createTextNode(DiagPage.AdapterType[i].name)); |
| adapterSelectionElement.appendChild(labelElement); |
| adapterSelectionElement.appendChild(document.createElement('br')); |
| } |
| }, |
| |
| /** |
| * Update the connectivity status for the specified network interface. |
| * @private |
| */ |
| updateConnectivityStatus_: function() { |
| var adapter = this.activeAdapter_; |
| var status = this.adapterStatus_[adapter]; |
| var name = DiagPage.AdapterType[adapter].name; |
| var kind = DiagPage.AdapterType[adapter].kind; |
| |
| // Status messages for individual tests. |
| var connectivityStatusElement = $('connectivity-status'); |
| var testStatusElements = new Array(); |
| removeChildren(connectivityStatusElement); |
| for (var i = 0; i < 3; i++) { |
| testStatusElements[i] = document.createElement('div'); |
| connectivityStatusElement.appendChild(testStatusElements[i]); |
| } |
| testStatusElements[0].innerHTML = |
| localStrings.getStringF('testing-hardware', name); |
| testStatusElements[1].innerHTML = |
| localStrings.getString('testing-connection-to-router'); |
| testStatusElements[2].innerHTML = |
| localStrings.getString('testing-connection-to-internet'); |
| |
| // Error and recommendation messages may be inserted in test status |
| // elements. |
| var errorElement = document.createElement('div'); |
| var recommendationElement = document.createElement('div'); |
| errorElement.className = 'test-error'; |
| recommendationElement.className = 'recommendation'; |
| testStatusElements[0].className = 'test-performed'; |
| if (status == DiagPage.AdapterStatus.DISABLED) { |
| errorElement.appendChild(DiagPage.FailIconElement.cloneNode()); |
| errorElement.appendChild(document.createTextNode( |
| localStrings.getStringF('adapter-disabled', name))); |
| recommendationElement.innerHTML = |
| localStrings.getStringF('enable-adapter', name); |
| connectivityStatusElement.insertBefore(errorElement, |
| testStatusElements[1]); |
| connectivityStatusElement.insertBefore(recommendationElement, |
| testStatusElements[1]); |
| testStatusElements[1].className = 'test-pending'; |
| testStatusElements[2].className = 'test-pending'; |
| } else { |
| testStatusElements[0].appendChild(DiagPage.TickIconElement.cloneNode()); |
| testStatusElements[1].className = 'test-performed'; |
| if (status == DiagPage.AdapterStatus.NO_IP) { |
| errorElement.appendChild(DiagPage.FailIconElement.cloneNode()); |
| errorElement.appendChild(document.createTextNode( |
| localStrings.getStringF('adapter-no-ip', name))); |
| recommendationElement.innerHTML = |
| localStrings.getStringF('fix-no-ip-' + kind); |
| connectivityStatusElement.insertBefore(errorElement, |
| testStatusElements[2]); |
| connectivityStatusElement.insertBefore(recommendationElement, |
| testStatusElements[2]); |
| testStatusElements[2].className = 'test-pending'; |
| } else { |
| testStatusElements[1].appendChild( |
| DiagPage.TickIconElement.cloneNode()); |
| testStatusElements[2].className = 'test-performed'; |
| if (this.pingTestStatus_ == DiagPage.PingTestStatus.NOT_STARTED || |
| this.pingTestStatus_ == DiagPage.PingTestStatus.IN_PROGRESS) { |
| // TODO(hshi): make the ellipsis below i18n-friendly. |
| testStatusElements[2].innerHTML += '...'; |
| } else { |
| if (this.pingTestStatus_ == DiagPage.PingTestStatus.FAILED) { |
| errorElement.appendChild(DiagPage.FailIconElement.cloneNode()); |
| errorElement.appendChild(document.createTextNode( |
| localStrings.getString('gateway-not-connected-to-internet'))); |
| recommendationElement.innerHTML = |
| localStrings.getStringF('fix-gateway-connection'); |
| connectivityStatusElement.appendChild(errorElement); |
| connectivityStatusElement.appendChild(recommendationElement); |
| } else { |
| testStatusElements[2].appendChild( |
| DiagPage.TickIconElement.cloneNode()); |
| } |
| } |
| } |
| } |
| } |
| }; |
| |
| DiagPage.setDeviceStatus = function(deviceStatus) { |
| DiagPage.getInstance().setDeviceStatus(deviceStatus); |
| } |
| |
| DiagPage.setTestICMPStatus = function(testICMPStatus) { |
| DiagPage.getInstance().setTestICMPStatus_(testICMPStatus); |
| } |
| |
| // Export |
| return { |
| DiagPage: DiagPage |
| }; |
| }); |
| |
| /** |
| * Initialize the DiagPage upon DOM content loaded. |
| */ |
| document.addEventListener('DOMContentLoaded', function() { |
| diag.DiagPage.getInstance().initialize(); |
| }); |