1 // Copyright (c) 2012 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.
5 var localStrings = new LocalStrings();
7 cr.define('diag', function() {
9 * Encapsulated handling of the diagnostics page.
11 function DiagPage() {}
13 cr.addSingletonGetter(DiagPage);
16 * Remove all children nodes for an element.
17 * @param {element} parent of the elements to be removed.
19 function removeChildren(element) {
20 element.textContent = '';
24 * List of network adapter types.
26 DiagPage.AdapterType = [
27 {adapter: 'wifi', name: localStrings.getString('wifi'), kind: 'wifi'},
28 {adapter: 'ethernet', name: localStrings.getString('ethernet1'),
30 {adapter: 'ethernet2', name: localStrings.getString('ethernet2'),
32 {adapter: 'cellular', name: localStrings.getString('3g'), kind: '3g'},
36 * List of network adapter status.
37 * The numeric value assigned to each status reflects how healthy the network
42 DiagPage.AdapterStatus = {
50 * List of ping test status.
51 * The numeric value assigned to each status reflects how much progress has
52 * been made for the ping test.
56 DiagPage.PingTestStatus = {
64 * Image elements for icons.
66 DiagPage.FailIconElement = document.createElement('img');
67 DiagPage.TickIconElement = document.createElement('img');
68 DiagPage.FailIconElement.setAttribute('src', 'chrome://diagnostics/fail.png');
69 DiagPage.TickIconElement.setAttribute('src', 'chrome://diagnostics/tick.png');
71 DiagPage.prototype = {
73 * Perform initial setup.
75 initialize: function() {
76 // Reset the diag page state.
79 // Register event handlers.
80 $('connectivity-refresh').addEventListener('click', function() {
81 if (!this.getNetifStatusInProgress_)
87 * Resets the diag page state.
90 // Initialize member variables.
91 this.activeAdapter_ = -1;
92 this.adapterStatus_ = new Array();
93 if (!this.pingTestStatus_ ||
94 this.pingTestStatus_ != DiagPage.PingTestStatus.IN_PROGRESS) {
95 this.pingTestStatus_ = DiagPage.PingTestStatus.NOT_STARTED;
98 // Initialize the UI with "loading" message.
99 $('loading').hidden = false;
100 $('choose-adapter').hidden = true;
101 removeChildren($('adapter-selection'));
102 removeChildren($('connectivity-status'));
104 // Call into Chrome to get network interfaces status.
105 chrome.send('getNetworkInterfaces');
106 this.getNetifStatusInProgress_ = true;
110 * Updates the connectivity status with the device information.
111 * @param {Object} deviceStatus Dictionary of network adapter status.
113 setDeviceStatus: function(deviceStatus) {
114 // Hide the "loading" message and show the "choose-adapter" message.
115 $('loading').hidden = true;
116 $('choose-adapter').hidden = false;
118 // Reset all adapters status.
119 var adapterLookup = {};
120 for (var i = 0; i < DiagPage.AdapterType.length; i++) {
121 this.adapterStatus_[i] = DiagPage.AdapterStatus.NOT_FOUND;
122 adapterLookup[DiagPage.AdapterType[i].adapter] = i;
125 // Update adapter status from data.
126 var foundValidIp = false;
127 for (var devicePath in deviceStatus) {
128 var device = deviceStatus[devicePath];
129 var type = device['Type'];
130 var idx = adapterLookup[type];
132 console.warning('Unexpected adapter type: ' + type);
136 // Special case for multiple ethernet adapters.
137 if (type == 'ethernet' &&
138 this.adapterStatus_[idx] != DiagPage.AdapterStatus.NOT_FOUND) {
140 idx = adapterLookup[type];
143 this.adapterStatus_[idx] = device['Powered'] == true ?
144 DiagPage.AdapterStatus.NO_IP : DiagPage.AdapterStatus.DISABLED;
145 var ipconfigs = device['ipconfigs'];
146 for (var ipconfigPath in ipconfigs) {
147 var ipconfig = ipconfigs[ipconfigPath];
148 if (ipconfig['Address']) {
149 this.adapterStatus_[idx] = DiagPage.AdapterStatus.VALID_IP;
155 // If we have valid IP, start ping test.
157 this.pingTestStatus_ == DiagPage.PingTestStatus.NOT_STARTED) {
158 this.pingTestStatus_ == DiagPage.PingTestStatus.IN_PROGRESS;
159 chrome.send('testICMP', [String('8.8.8.8')]);
163 this.updateAdapterSelection_();
164 this.updateConnectivityStatus_();
166 // Clear the getNetifStatusInProgress flag.
167 this.getNetifStatusInProgress_ = false;
171 * Updates the ICMP connectivity status.
172 * @param {Object} testICMPStatus Dictionary of ICMP connectivity status.
174 setTestICMPStatus_: function(testICMPStatus) {
175 // Update the ping test state.
176 for (var prop in testICMPStatus) {
177 var status = testICMPStatus[prop];
178 if (status.sent && status.recvd && status.sent == status.recvd)
179 this.pingTestStatus_ = DiagPage.PingTestStatus.SUCCEEDED;
181 this.pingTestStatus_ = DiagPage.PingTestStatus.FAILED;
186 this.updateConnectivityStatus_();
190 * Gets the HTML radio input element id for a network adapter.
193 getAdapterElementId_: function(adapter) {
194 return 'adapter-' + DiagPage.AdapterType[adapter].adapter;
198 * Gets the most active adapter based on their status.
201 getActiveAdapter_: function() {
202 var activeAdapter = -1;
203 var activeAdapterStatus = DiagPage.AdapterStatus.NOT_FOUND;
204 for (var i = 0; i < DiagPage.AdapterType.length; i++) {
205 var status = this.adapterStatus_[i];
206 if (status == DiagPage.AdapterStatus.NOT_FOUND)
208 if (activeAdapter == -1 || status > activeAdapterStatus) {
210 activeAdapterStatus = status;
213 return activeAdapter;
217 * Update the adapter selection section.
220 updateAdapterSelection_: function() {
221 // Determine active adapter.
222 if (this.activeAdapter_ == -1)
223 this.activeAdapter_ = this.getActiveAdapter_();
224 // Clear adapter selection section.
225 var adapterSelectionElement = $('adapter-selection');
226 removeChildren(adapterSelectionElement);
227 // Create HTML radio input elements.
228 for (var i = 0; i < DiagPage.AdapterType.length; i++) {
229 if (this.adapterStatus_[i] == DiagPage.AdapterStatus.NOT_FOUND)
231 var radioElement = document.createElement('input');
232 var elementId = this.getAdapterElementId_(i);
233 radioElement.setAttribute('type', 'radio');
234 radioElement.setAttribute('name', 'adapter');
235 radioElement.setAttribute('id', elementId);
236 if (i == this.activeAdapter_)
237 radioElement.setAttribute('checked', 'true');
238 radioElement.onclick = function(adapter) {
239 this.activeAdapter_ = adapter;
240 this.updateConnectivityStatus_();
242 var labelElement = document.createElement('label');
243 labelElement.setAttribute('for', elementId);
244 labelElement.appendChild(radioElement);
245 labelElement.appendChild(
246 document.createTextNode(DiagPage.AdapterType[i].name));
247 adapterSelectionElement.appendChild(labelElement);
248 adapterSelectionElement.appendChild(document.createElement('br'));
253 * Update the connectivity status for the specified network interface.
256 updateConnectivityStatus_: function() {
257 var adapter = this.activeAdapter_;
258 var status = this.adapterStatus_[adapter];
259 var name = DiagPage.AdapterType[adapter].name;
260 var kind = DiagPage.AdapterType[adapter].kind;
262 // Status messages for individual tests.
263 var connectivityStatusElement = $('connectivity-status');
264 var testStatusElements = new Array();
265 removeChildren(connectivityStatusElement);
266 for (var i = 0; i < 3; i++) {
267 testStatusElements[i] = document.createElement('div');
268 connectivityStatusElement.appendChild(testStatusElements[i]);
270 testStatusElements[0].innerHTML =
271 localStrings.getStringF('testing-hardware', name);
272 testStatusElements[1].innerHTML =
273 localStrings.getString('testing-connection-to-router');
274 testStatusElements[2].innerHTML =
275 localStrings.getString('testing-connection-to-internet');
277 // Error and recommendation messages may be inserted in test status
279 var errorElement = document.createElement('div');
280 var recommendationElement = document.createElement('div');
281 errorElement.className = 'test-error';
282 recommendationElement.className = 'recommendation';
283 testStatusElements[0].className = 'test-performed';
284 if (status == DiagPage.AdapterStatus.DISABLED) {
285 errorElement.appendChild(DiagPage.FailIconElement.cloneNode());
286 errorElement.appendChild(document.createTextNode(
287 localStrings.getStringF('adapter-disabled', name)));
288 recommendationElement.innerHTML =
289 localStrings.getStringF('enable-adapter', name);
290 connectivityStatusElement.insertBefore(errorElement,
291 testStatusElements[1]);
292 connectivityStatusElement.insertBefore(recommendationElement,
293 testStatusElements[1]);
294 testStatusElements[1].className = 'test-pending';
295 testStatusElements[2].className = 'test-pending';
297 testStatusElements[0].appendChild(DiagPage.TickIconElement.cloneNode());
298 testStatusElements[1].className = 'test-performed';
299 if (status == DiagPage.AdapterStatus.NO_IP) {
300 errorElement.appendChild(DiagPage.FailIconElement.cloneNode());
301 errorElement.appendChild(document.createTextNode(
302 localStrings.getStringF('adapter-no-ip', name)));
303 recommendationElement.innerHTML =
304 localStrings.getStringF('fix-no-ip-' + kind);
305 connectivityStatusElement.insertBefore(errorElement,
306 testStatusElements[2]);
307 connectivityStatusElement.insertBefore(recommendationElement,
308 testStatusElements[2]);
309 testStatusElements[2].className = 'test-pending';
311 testStatusElements[1].appendChild(
312 DiagPage.TickIconElement.cloneNode());
313 testStatusElements[2].className = 'test-performed';
314 if (this.pingTestStatus_ == DiagPage.PingTestStatus.NOT_STARTED ||
315 this.pingTestStatus_ == DiagPage.PingTestStatus.IN_PROGRESS) {
316 // TODO(hshi): make the ellipsis below i18n-friendly.
317 testStatusElements[2].innerHTML += '...';
319 if (this.pingTestStatus_ == DiagPage.PingTestStatus.FAILED) {
320 errorElement.appendChild(DiagPage.FailIconElement.cloneNode());
321 errorElement.appendChild(document.createTextNode(
322 localStrings.getString('gateway-not-connected-to-internet')));
323 recommendationElement.innerHTML =
324 localStrings.getStringF('fix-gateway-connection');
325 connectivityStatusElement.appendChild(errorElement);
326 connectivityStatusElement.appendChild(recommendationElement);
328 testStatusElements[2].appendChild(
329 DiagPage.TickIconElement.cloneNode());
337 DiagPage.setDeviceStatus = function(deviceStatus) {
338 DiagPage.getInstance().setDeviceStatus(deviceStatus);
341 DiagPage.setTestICMPStatus = function(testICMPStatus) {
342 DiagPage.getInstance().setTestICMPStatus_(testICMPStatus);
352 * Initialize the DiagPage upon DOM content loaded.
354 document.addEventListener('DOMContentLoaded', function() {
355 diag.DiagPage.getInstance().initialize();