- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / chromeos / diagnostics / main.js
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.
4
5 var localStrings = new LocalStrings();
6
7 cr.define('diag', function() {
8   /**
9    * Encapsulated handling of the diagnostics page.
10    */
11   function DiagPage() {}
12
13   cr.addSingletonGetter(DiagPage);
14
15   /*
16    * Remove all children nodes for an element.
17    * @param {element} parent of the elements to be removed.
18    */
19   function removeChildren(element) {
20     element.textContent = '';
21   }
22
23   /**
24    * List of network adapter types.
25    */
26   DiagPage.AdapterType = [
27       {adapter: 'wifi', name: localStrings.getString('wifi'), kind: 'wifi'},
28       {adapter: 'ethernet', name: localStrings.getString('ethernet1'),
29        kind: 'ethernet'},
30       {adapter: 'ethernet2', name: localStrings.getString('ethernet2'),
31        kind: 'ethernet'},
32       {adapter: 'cellular', name: localStrings.getString('3g'), kind: '3g'},
33   ];
34
35   /**
36    * List of network adapter status.
37    * The numeric value assigned to each status reflects how healthy the network
38    * adapter is.
39    *
40    * @enum {int}
41    */
42   DiagPage.AdapterStatus = {
43       NOT_FOUND: 0,
44       DISABLED: 1,
45       NO_IP: 2,
46       VALID_IP: 3
47   };
48
49   /**
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.
53    *
54    * @enum {int}
55    */
56   DiagPage.PingTestStatus = {
57       NOT_STARTED: 0,
58       IN_PROGRESS: 1,
59       FAILED: 2,
60       SUCCEEDED: 3
61   };
62
63   /**
64    * Image elements for icons.
65    */
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');
70
71   DiagPage.prototype = {
72     /**
73      * Perform initial setup.
74      */
75     initialize: function() {
76       // Reset the diag page state.
77       this.reset_();
78
79       // Register event handlers.
80       $('connectivity-refresh').addEventListener('click', function() {
81         if (!this.getNetifStatusInProgress_)
82           this.reset_();
83       }.bind(this));
84     },
85
86     /**
87      * Resets the diag page state.
88      */
89     reset_: function() {
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;
96       }
97
98       // Initialize the UI with "loading" message.
99       $('loading').hidden = false;
100       $('choose-adapter').hidden = true;
101       removeChildren($('adapter-selection'));
102       removeChildren($('connectivity-status'));
103
104       // Call into Chrome to get network interfaces status.
105       chrome.send('getNetworkInterfaces');
106       this.getNetifStatusInProgress_ = true;
107     },
108
109     /**
110      * Updates the connectivity status with the device information.
111      * @param {Object} deviceStatus Dictionary of network adapter status.
112      */
113     setDeviceStatus: function(deviceStatus) {
114       // Hide the "loading" message and show the "choose-adapter" message.
115       $('loading').hidden = true;
116       $('choose-adapter').hidden = false;
117
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;
123       }
124
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];
131         if (idx == null) {
132           console.warning('Unexpected adapter type: ' + type);
133           continue;
134         }
135
136         // Special case for multiple ethernet adapters.
137         if (type == 'ethernet' &&
138             this.adapterStatus_[idx] != DiagPage.AdapterStatus.NOT_FOUND) {
139           type = 'ethernet2';
140           idx = adapterLookup[type];
141         }
142
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;
150             foundValidIp = true;
151           }
152         }
153       }
154
155       // If we have valid IP, start ping test.
156       if (foundValidIp &&
157           this.pingTestStatus_ == DiagPage.PingTestStatus.NOT_STARTED) {
158         this.pingTestStatus_ == DiagPage.PingTestStatus.IN_PROGRESS;
159         chrome.send('testICMP', [String('8.8.8.8')]);
160       }
161
162       // Update UI
163       this.updateAdapterSelection_();
164       this.updateConnectivityStatus_();
165
166       // Clear the getNetifStatusInProgress flag.
167       this.getNetifStatusInProgress_ = false;
168     },
169
170     /**
171      * Updates the ICMP connectivity status.
172      * @param {Object} testICMPStatus Dictionary of ICMP connectivity status.
173      */
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;
180         else
181           this.pingTestStatus_ = DiagPage.PingTestStatus.FAILED;
182         break;
183       }
184
185       // Update UI
186       this.updateConnectivityStatus_();
187     },
188
189     /**
190      * Gets the HTML radio input element id for a network adapter.
191      * @private
192      */
193     getAdapterElementId_: function(adapter) {
194       return 'adapter-' + DiagPage.AdapterType[adapter].adapter;
195     },
196
197     /**
198      * Gets the most active adapter based on their status.
199      * @private
200      */
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)
207           continue;
208         if (activeAdapter == -1 || status > activeAdapterStatus) {
209           activeAdapter = i;
210           activeAdapterStatus = status;
211         }
212       }
213       return activeAdapter;
214     },
215
216     /**
217      * Update the adapter selection section.
218      * @private
219      */
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)
230           continue;
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_();
241         }.bind(this, i);
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'));
249       }
250     },
251
252     /**
253      * Update the connectivity status for the specified network interface.
254      * @private
255      */
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;
261
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]);
269       }
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');
276
277       // Error and recommendation messages may be inserted in test status
278       // elements.
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';
296       } else {
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';
310         } else {
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 += '...';
318           } else {
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);
327             } else {
328               testStatusElements[2].appendChild(
329                 DiagPage.TickIconElement.cloneNode());
330             }
331           }
332         }
333       }
334     }
335   };
336
337   DiagPage.setDeviceStatus = function(deviceStatus) {
338     DiagPage.getInstance().setDeviceStatus(deviceStatus);
339   }
340
341   DiagPage.setTestICMPStatus = function(testICMPStatus) {
342     DiagPage.getInstance().setTestICMPStatus_(testICMPStatus);
343   }
344
345   // Export
346   return {
347     DiagPage: DiagPage
348   };
349 });
350
351 /**
352  * Initialize the DiagPage upon DOM content loaded.
353  */
354 document.addEventListener('DOMContentLoaded', function() {
355   diag.DiagPage.getInstance().initialize();
356 });