Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / resources / options / chromeos / internet_detail.js
blob843b54b77a1e3b5b22cebb86a064af22afa9ffc4
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 // require: onc_data.js
7 // NOTE(stevenjb): This code is in the process of being converted to be
8 // compatible with the networkingPrivate extension API:
9 // * The network property dictionaries are being converted to use ONC values.
10 // * chrome.send calls will be replaced with chrome.networkingPrivate calls.
11 // See crbug.com/279351 for more info.
13 cr.define('options.internet', function() {
14   var OncData = cr.onc.OncData;
15   var Page = cr.ui.pageManager.Page;
16   var PageManager = cr.ui.pageManager.PageManager;
17   /** @const */ var IPAddressField = options.internet.IPAddressField;
19   /** @const */ var GoogleNameServers = ['8.8.4.4', '8.8.8.8'];
20   /** @const */ var CarrierSprint = 'Sprint';
21   /** @const */ var CarrierVerizon = 'Verizon Wireless';
23   /**
24    * Helper function to set hidden attribute for elements matching a selector.
25    * @param {string} selector CSS selector for extracting a list of elements.
26    * @param {boolean} hidden New hidden value.
27    */
28   function updateHidden(selector, hidden) {
29     var elements = cr.doc.querySelectorAll(selector);
30     for (var i = 0, el; el = elements[i]; i++) {
31       el.hidden = hidden;
32     }
33   }
35   /**
36    * Helper function to update the properties of the data object from the
37    * properties in the update object.
38    * @param {Object} data Object to update.
39    * @param {Object} update Object containing the updated properties.
40    */
41   function updateDataObject(data, update) {
42     for (var prop in update) {
43       if (prop in data)
44         data[prop] = update[prop];
45     }
46   }
48   /**
49    * Monitor pref change of given element.
50    * @param {Element} el Target element.
51    */
52   function observePrefsUI(el) {
53     Preferences.getInstance().addEventListener(el.pref, handlePrefUpdate);
54   }
56   /**
57    * UI pref change handler.
58    * @param {Event} e The update event.
59    */
60   function handlePrefUpdate(e) {
61     DetailsInternetPage.getInstance().updateControls();
62   }
64   /**
65    * Simple helper method for converting a field to a string. It is used to
66    * easily assign an empty string from fields that may be unknown or undefined.
67    * @param {Object} value that should be converted to a string.
68    * @return {string} the result.
69    */
70   function stringFromValue(value) {
71     return value ? String(value) : '';
72   }
74   /**
75    * @param {string} action An action to send to coreOptionsUserMetricsAction.
76    */
77   function sendChromeMetricsAction(action) {
78     chrome.send('coreOptionsUserMetricsAction', [action]);
79   }
81   /**
82    * Send metrics to Chrome when the detailed page is opened.
83    * @param {string} type The ONC type of the network being shown.
84    * @param {string} state The ONC network state.
85    */
86   function sendShowDetailsMetrics(type, state) {
87     if (type == 'WiFi') {
88       sendChromeMetricsAction('Options_NetworkShowDetailsWifi');
89       if (state != 'NotConnected')
90         sendChromeMetricsAction('Options_NetworkShowDetailsWifiConnected');
91     } else if (type == 'Cellular') {
92       sendChromeMetricsAction('Options_NetworkShowDetailsCellular');
93       if (state != 'NotConnected')
94         sendChromeMetricsAction('Options_NetworkShowDetailsCellularConnected');
95     } else if (type == 'VPN') {
96       sendChromeMetricsAction('Options_NetworkShowDetailsVPN');
97       if (state != 'NotConnected')
98         sendChromeMetricsAction('Options_NetworkShowDetailsVPNConnected');
99     }
100   }
102   /**
103    * Returns the netmask as a string for a given prefix length.
104    * @param {number} prefixLength The ONC routing prefix length.
105    * @return {string} The corresponding netmask.
106    */
107   function prefixLengthToNetmask(prefixLength) {
108     // Return the empty string for invalid inputs.
109     if (prefixLength < 0 || prefixLength > 32)
110       return '';
111     var netmask = '';
112     for (var i = 0; i < 4; ++i) {
113       var remainder = 8;
114       if (prefixLength >= 8) {
115         prefixLength -= 8;
116       } else {
117         remainder = prefixLength;
118         prefixLength = 0;
119       }
120       if (i > 0)
121         netmask += '.';
122       var value = 0;
123       if (remainder != 0)
124         value = ((2 << (remainder - 1)) - 1) << (8 - remainder);
125       netmask += value.toString();
126     }
127     return netmask;
128   }
130   /**
131    * Returns the prefix length from the netmask string.
132    * @param {string} netmask The netmask string, e.g. 255.255.255.0.
133    * @return {number} The corresponding netmask or -1 if invalid.
134    */
135   function netmaskToPrefixLength(netmask) {
136     var prefixLength = 0;
137     var tokens = netmask.split('.');
138     if (tokens.length != 4)
139       return -1;
140     for (var i = 0; i < tokens.length; ++i) {
141       var token = tokens[i];
142       // If we already found the last mask and the current one is not
143       // '0' then the netmask is invalid. For example, 255.224.255.0
144       if (prefixLength / 8 != i) {
145         if (token != '0')
146           return -1;
147       } else if (token == '255') {
148         prefixLength += 8;
149       } else if (token == '254') {
150         prefixLength += 7;
151       } else if (token == '252') {
152         prefixLength += 6;
153       } else if (token == '248') {
154         prefixLength += 5;
155       } else if (token == '240') {
156         prefixLength += 4;
157       } else if (token == '224') {
158         prefixLength += 3;
159       } else if (token == '192') {
160         prefixLength += 2;
161       } else if (token == '128') {
162         prefixLength += 1;
163       } else if (token == '0') {
164         prefixLength += 0;
165       } else {
166         // mask is not a valid number.
167         return -1;
168       }
169     }
170     return prefixLength;
171   }
173   // Returns true if we should show the 'View Account' button for |onc|.
174   // TODO(stevenjb): We should query the Mobile Config API for whether or not to
175   // show the 'View Account' button once it is integrated with Settings.
176   function shouldShowViewAccountButton(onc) {
177     var activationState = onc.getActiveValue('Cellular.ActivationState');
178     if (activationState != 'Activating' && activationState != 'Activated')
179       return false;
181     // If no online payment URL was provided by Shill, only show 'View Account'
182     // for Verizon Wireless.
183     if (!onc.getActiveValue('Cellular.PaymentPortal.Url') &&
184         onc.getActiveValue('Cellular.Carrier') != CarrierVerizon) {
185       return false;
186     }
188     // 'View Account' should only be shown for connected networks, or
189     // disconnected LTE networks with a valid MDN.
190     var connectionState = onc.getActiveValue('ConnectionState');
191     if (connectionState != 'Connected') {
192       var technology = onc.getActiveValue('Cellular.NetworkTechnology');
193       if (technology != 'LTE' && technology != 'LTEAdvanced')
194         return false;
195       if (!onc.getActiveValue('Cellular.MDN'))
196         return false;
197     }
199     return true;
200   }
202   /////////////////////////////////////////////////////////////////////////////
203   // DetailsInternetPage class:
205   /**
206    * Encapsulated handling of ChromeOS internet details overlay page.
207    * @constructor
208    * @extends {cr.ui.pageManager.Page}
209    */
210   function DetailsInternetPage() {
211     // If non-negative, indicates a custom entry in select-apn.
212     this.userApnIndex_ = -1;
214     // The custom APN properties associated with entry |userApnIndex_|.
215     this.userApn_ = {};
217     // The currently selected APN entry in $('select-apn') (which may or may not
218     // == userApnIndex_).
219     this.selectedApnIndex_ = -1;
221     // We show the Proxy configuration tab for remembered networks and when
222     // configuring a proxy from the login screen.
223     this.showProxy_ = false;
225     Page.call(this, 'detailsInternetPage', '', 'details-internet-page');
226   }
228   cr.addSingletonGetter(DetailsInternetPage);
230   DetailsInternetPage.prototype = {
231     __proto__: Page.prototype,
233     /** @override */
234     initializePage: function() {
235       Page.prototype.initializePage.call(this);
236       this.initializePageContents_();
238       chrome.networkingPrivate.onNetworksChanged.addListener(
239           this.onNetworksChanged_.bind(this));
241       this.showNetworkDetails_();
242     },
244     /**
245      * Automatically shows the network details dialog if network information
246      * is included in the URL.
247      */
248     showNetworkDetails_: function() {
249       var guid = parseQueryParams(window.location).guid;
250       if (!guid || !guid.length)
251         return;
252       chrome.networkingPrivate.getManagedProperties(
253           guid, DetailsInternetPage.initializeDetailsPage);
254     },
256     /**
257      * networkingPrivate callback when networks change.
258      * @param {Array<string>} changes List of GUIDs whose properties have
259      *     changed.
260      * @private
261      */
262     onNetworksChanged_: function(changes) {
263       if (!this.onc_)
264         return;
265       var guid = this.onc_.guid();
266       if (changes.indexOf(guid) != -1) {
267         chrome.networkingPrivate.getManagedProperties(
268           guid, DetailsInternetPage.updateConnectionData);
269       }
270     },
272     /**
273      * Initializes the contents of the page.
274      */
275     initializePageContents_: function() {
276       $('details-internet-dismiss').addEventListener('click', function(event) {
277         DetailsInternetPage.setDetails();
278       });
280       $('details-internet-login').addEventListener('click', function(event) {
281         DetailsInternetPage.setDetails();
282         DetailsInternetPage.loginFromDetails();
283       });
285       $('details-internet-disconnect').addEventListener('click',
286                                                         function(event) {
287         DetailsInternetPage.setDetails();
288         DetailsInternetPage.disconnectNetwork();
289       });
291       $('details-internet-configure').addEventListener('click',
292                                                        function(event) {
293         DetailsInternetPage.setDetails();
294         DetailsInternetPage.configureNetwork();
295       });
297       $('activate-details').addEventListener('click', function(event) {
298         DetailsInternetPage.activateFromDetails();
299       });
301       $('view-account-details').addEventListener('click', function(event) {
302         chrome.send('showMorePlanInfo',
303                     [DetailsInternetPage.getInstance().onc_.guid()]);
304         PageManager.closeOverlay();
305       });
307       $('cellular-apn-use-default').addEventListener('click', function(event) {
308         DetailsInternetPage.getInstance().setDefaultApn_();
309       });
311       $('cellular-apn-set').addEventListener('click', function(event) {
312         DetailsInternetPage.getInstance().setApn_($('cellular-apn').value);
313       });
315       $('cellular-apn-cancel').addEventListener('click', function(event) {
316         DetailsInternetPage.getInstance().cancelApn_();
317       });
319       $('select-apn').addEventListener('change', function(event) {
320         DetailsInternetPage.getInstance().selectApn_();
321       });
323       $('sim-card-lock-enabled').addEventListener('click', function(event) {
324         var newValue = $('sim-card-lock-enabled').checked;
325         // Leave value as is because user needs to enter PIN code first.
326         // When PIN will be entered and value changed,
327         // we'll update UI to reflect that change.
328         $('sim-card-lock-enabled').checked = !newValue;
329         var operation = newValue ? 'setLocked' : 'setUnlocked';
330         chrome.send('simOperation', [operation]);
331       });
332       $('change-pin').addEventListener('click', function(event) {
333         chrome.send('simOperation', ['changePin']);
334       });
336       // Proxy
337       ['proxy-host-single-port',
338        'secure-proxy-port',
339        'socks-port',
340        'ftp-proxy-port',
341        'proxy-host-port'
342       ].forEach(function(id) {
343         options.PrefPortNumber.decorate($(id));
344       });
346       options.proxyexceptions.ProxyExceptions.decorate($('ignored-host-list'));
347       $('remove-host').addEventListener('click',
348                                         this.handleRemoveProxyExceptions_);
349       $('add-host').addEventListener('click', this.handleAddProxyException_);
350       $('direct-proxy').addEventListener('click', this.disableManualProxy_);
351       $('manual-proxy').addEventListener('click', this.enableManualProxy_);
352       $('auto-proxy').addEventListener('click', this.disableManualProxy_);
353       $('proxy-all-protocols').addEventListener('click',
354                                                 this.toggleSingleProxy_);
355       $('proxy-use-pac-url').addEventListener('change',
356                                               this.handleAutoConfigProxy_);
358       observePrefsUI($('direct-proxy'));
359       observePrefsUI($('manual-proxy'));
360       observePrefsUI($('auto-proxy'));
361       observePrefsUI($('proxy-all-protocols'));
362       observePrefsUI($('proxy-use-pac-url'));
364       $('ip-automatic-configuration-checkbox').addEventListener('click',
365         this.handleIpAutoConfig_);
366       $('automatic-dns-radio').addEventListener('click',
367         this.handleNameServerTypeChange_);
368       $('google-dns-radio').addEventListener('click',
369         this.handleNameServerTypeChange_);
370       $('user-dns-radio').addEventListener('click',
371         this.handleNameServerTypeChange_);
373       // We only load this string if we have the string data available
374       // because the proxy settings page on the login screen re-uses the
375       // proxy sub-page from the internet options, and it doesn't ever
376       // show the DNS settings, so we don't need this string there.
377       // The string isn't available because
378       // chrome://settings-frame/strings.js (where the string is
379       // stored) is not accessible from the login screen.
380       // TODO(pneubeck): Remove this once i18n of the proxy dialog on the login
381       // page is fixed. http://crbug.com/242865
382       if (loadTimeData.data_) {
383         $('google-dns-label').innerHTML =
384             loadTimeData.getString('googleNameServers');
385       }
386     },
388     /**
389      * Handler for "add" event fired from userNameEdit.
390      * @param {Event} e Add event fired from userNameEdit.
391      * @private
392      */
393     handleAddProxyException_: function(e) {
394       var exception = $('new-host').value;
395       $('new-host').value = '';
397       exception = exception.trim();
398       if (exception)
399         $('ignored-host-list').addException(exception);
400     },
402     /**
403      * Handler for when the remove button is clicked
404      * @param {Event} e The click event.
405      * @private
406      */
407     handleRemoveProxyExceptions_: function(e) {
408       var selectedItems = $('ignored-host-list').selectedItems;
409       for (var x = 0; x < selectedItems.length; x++) {
410         $('ignored-host-list').removeException(selectedItems[x]);
411       }
412     },
414     /**
415      * Handler for when the IP automatic configuration checkbox is clicked.
416      * @param {Event} e The click event.
417      * @private
418      */
419     handleIpAutoConfig_: function(e) {
420       var checked = $('ip-automatic-configuration-checkbox').checked;
421       var fields = [$('ip-address'), $('ip-netmask'), $('ip-gateway')];
422       for (var i = 0; i < fields.length; ++i) {
423         fields[i].editable = !checked;
424         if (checked) {
425           var model = fields[i].model;
426           model.value = model.automatic;
427           fields[i].model = model;
428         }
429       }
430       if (!checked)
431         $('ip-address').focus();
432     },
434     /**
435      * Handler for when the name server selection changes.
436      * @param {Event} event The click event.
437      * @private
438      */
439     handleNameServerTypeChange_: function(event) {
440       var type = event.target.value;
441       DetailsInternetPage.updateNameServerDisplay(type);
442     },
444     /**
445      * Gets the IPConfig ONC Object.
446      * @param {string} nameServerType The selected name server type:
447      *   'automatic', 'google', or 'user'.
448      * @return {Object} The IPConfig ONC object.
449      * @private
450      */
451     getIpConfig_: function(nameServerType) {
452       var ipConfig = {};
453       // If 'ip-address' is empty, automatic configuration will be used.
454       if (!$('ip-automatic-configuration-checkbox').checked &&
455           $('ip-address').model.value) {
456         ipConfig['IPAddress'] = $('ip-address').model.value;
457         var netmask = $('ip-netmask').model.value;
458         var routingPrefix = 0;
459         if (netmask) {
460           routingPrefix = netmaskToPrefixLength(netmask);
461           if (routingPrefix == -1) {
462             console.error('Invalid netmask: ' + netmask);
463             routingPrefix = 0;
464           }
465         }
466         ipConfig['RoutingPrefix'] = routingPrefix;
467         ipConfig['Gateway'] = $('ip-gateway').model.value || '';
468       }
470       // Note: If no nameserver fields are set, automatic configuration will be
471       // used. TODO(stevenjb): Validate input fields.
472       if (nameServerType != 'automatic') {
473         var userNameServers = [];
474         if (nameServerType == 'google') {
475           userNameServers = GoogleNameServers.slice();
476         } else if (nameServerType == 'user') {
477           for (var i = 1; i <= 4; ++i) {
478             var nameServerField = $('ipconfig-dns' + i);
479             // Skip empty values.
480             if (nameServerField && nameServerField.model &&
481                 nameServerField.model.value) {
482               userNameServers.push(nameServerField.model.value);
483             }
484           }
485         }
486         if (userNameServers.length)
487           ipConfig['NameServers'] = userNameServers.sort();
488       }
489       return ipConfig;
490     },
492     /**
493      * Creates an indicator event for controlled properties using
494      * the same dictionary format as CoreOptionsHandler::CreateValueForPref.
495      * @param {string} name The name for the Event.
496      * @param {{value: *, controlledBy: *, recommendedValue: *}} propData
497      *     Property dictionary.
498      * @private
499      */
500     createControlledEvent_: function(name, propData) {
501       assert('value' in propData && 'controlledBy' in propData &&
502              'recommendedValue' in propData);
503       var event = new Event(name);
504       event.value = {
505         value: propData.value,
506         controlledBy: propData.controlledBy,
507         recommendedValue: propData.recommendedValue
508       };
509       return event;
510     },
512     /**
513      * Creates an indicator event for controlled properties using
514      * the ONC getManagedProperties dictionary format.
515      * @param {string} name The name for the Event.
516      * @param {Object} propData ONC managed network property dictionary.
517      * @private
518      */
519     createManagedEvent_: function(name, propData) {
520       var event = new Event(name);
521       event.value = {};
523       // Set the current value and recommended value.
524       var activeValue = propData['Active'];
525       var effective = propData['Effective'];
526       if (activeValue == undefined)
527         activeValue = propData[effective];
528       event.value.value = activeValue;
530       // If a property is editable then it is not enforced, and 'controlledBy'
531       // is set to 'recommended' unless effective == {User|Shared}Setting, in
532       // which case the value was modified from the recommended value.
533       // Otherwise if 'Effective' is set to 'UserPolicy' or 'DevicePolicy' then
534       // the set value is mandated by the policy.
535       if (propData['UserEditable']) {
536         if (effective == 'UserPolicy')
537           event.value.controlledBy = 'recommended';
538         event.value.recommendedValue = propData['UserPolicy'];
539       } else if (propData['DeviceEditable']) {
540         if (effective == 'DevicePolicy')
541           event.value.controlledBy = 'recommended';
542         event.value.recommendedValue = propData['DevicePolicy'];
543       } else if (effective == 'UserPolicy' || effective == 'DevicePolicy') {
544         event.value.controlledBy = 'policy';
545       }
547       return event;
548     },
550     /**
551      * Update details page controls.
552      */
553     updateControls: function() {
554       // Note: onc may be undefined when called from a pref update before
555       // initialized in initializeDetailsPage.
556       var onc = this.onc_;
558       // Always show the ipconfig section. TODO(stevenjb): Improve the display
559       // for unconnected networks. Currently the IP address fields may be
560       // blank if the network is not connected.
561       $('ipconfig-section').hidden = false;
562       $('ipconfig-dns-section').hidden = false;
564       // Network type related.
565       updateHidden('#details-internet-page .cellular-details',
566                    this.type_ != 'Cellular');
567       updateHidden('#details-internet-page .wifi-details',
568                    this.type_ != 'WiFi');
569       updateHidden('#details-internet-page .wimax-details',
570                    this.type_ != 'WiMAX');
571       updateHidden('#details-internet-page .vpn-details', this.type_ != 'VPN');
572       updateHidden('#details-internet-page .proxy-details', !this.showProxy_);
574       // Cellular
575       if (onc && this.type_ == 'Cellular') {
576         // Hide gsm/cdma specific elements.
577         if (onc.getActiveValue('Cellular.Family') == 'GSM')
578           updateHidden('#details-internet-page .cdma-only', true);
579         else
580           updateHidden('#details-internet-page .gsm-only', true);
581       }
583       // Wifi
585       // Hide network tab for VPN.
586       updateHidden('#details-internet-page .network-details',
587                    this.type_ == 'VPN');
589       // Password and shared.
590       var source = onc ? onc.getSource() : 'None';
591       var shared = (source == 'Device' || source == 'DevicePolicy');
592       var security = onc ? onc.getWiFiSecurity() : 'None';
593       updateHidden('#details-internet-page #password-details',
594                    this.type_ != 'WiFi' || security == 'None');
595       updateHidden('#details-internet-page #wifi-shared-network', !shared);
596       updateHidden('#details-internet-page #prefer-network', source == 'None');
598       // WiMAX.
599       updateHidden('#details-internet-page #wimax-shared-network', !shared);
601       // Proxy
602       this.updateProxyBannerVisibility_();
603       this.toggleSingleProxy_();
604       if ($('manual-proxy').checked)
605         this.enableManualProxy_();
606       else
607         this.disableManualProxy_();
608     },
610     /**
611      * Updates info banner visibility state. This function shows the banner
612      * if proxy is managed or shared-proxies is off for shared network.
613      * @private
614      */
615     updateProxyBannerVisibility_: function() {
616       var bannerDiv = $('network-proxy-info-banner');
617       if (!loadTimeData.data_) {
618         // TODO(pneubeck): This temporarily prevents an exception below until
619         // i18n of the proxy dialog on the login page is
620         // fixed. http://crbug.com/242865
621         bannerDiv.hidden = true;
622         return;
623       }
625       // Show banner and determine its message if necessary.
626       var controlledBy = $('direct-proxy').controlledBy;
627       if (!controlledBy || controlledBy == '') {
628         bannerDiv.hidden = true;
629       } else {
630         bannerDiv.hidden = false;
631         // The possible banner texts are loaded in proxy_handler.cc.
632         var bannerText = 'proxyBanner' + controlledBy.charAt(0).toUpperCase() +
633                          controlledBy.slice(1);
634         $('banner-text').textContent = loadTimeData.getString(bannerText);
635       }
636     },
638     /**
639      * Handler for when the user clicks on the checkbox to allow a
640      * single proxy usage.
641      * @private
642      */
643     toggleSingleProxy_: function() {
644       if ($('proxy-all-protocols').checked) {
645         $('multi-proxy').hidden = true;
646         $('single-proxy').hidden = false;
647       } else {
648         $('multi-proxy').hidden = false;
649         $('single-proxy').hidden = true;
650       }
651     },
653     /**
654      * Handler for when the user clicks on the checkbox to enter
655      * auto configuration URL.
656      * @private
657      */
658     handleAutoConfigProxy_: function() {
659       $('proxy-pac-url').disabled = !$('proxy-use-pac-url').checked;
660     },
662     /**
663      * Handler for selecting a radio button that will disable the manual
664      * controls.
665      * @private
666      */
667     disableManualProxy_: function() {
668       $('ignored-host-list').disabled = true;
669       $('new-host').disabled = true;
670       $('remove-host').disabled = true;
671       $('add-host').disabled = true;
672       $('proxy-all-protocols').disabled = true;
673       $('proxy-host-name').disabled = true;
674       $('proxy-host-port').disabled = true;
675       $('proxy-host-single-name').disabled = true;
676       $('proxy-host-single-port').disabled = true;
677       $('secure-proxy-host-name').disabled = true;
678       $('secure-proxy-port').disabled = true;
679       $('ftp-proxy').disabled = true;
680       $('ftp-proxy-port').disabled = true;
681       $('socks-host').disabled = true;
682       $('socks-port').disabled = true;
683       $('proxy-use-pac-url').disabled = $('auto-proxy').disabled ||
684                                         !$('auto-proxy').checked;
685       $('proxy-pac-url').disabled = $('proxy-use-pac-url').disabled ||
686                                     !$('proxy-use-pac-url').checked;
687       $('auto-proxy-parms').hidden = !$('auto-proxy').checked;
688       $('manual-proxy-parms').hidden = !$('manual-proxy').checked;
689       sendChromeMetricsAction('Options_NetworkManualProxy_Disable');
690     },
692     /**
693      * Handler for selecting a radio button that will enable the manual
694      * controls.
695      * @private
696      */
697     enableManualProxy_: function() {
698       $('ignored-host-list').redraw();
699       var allDisabled = $('manual-proxy').disabled;
700       $('ignored-host-list').disabled = allDisabled;
701       $('new-host').disabled = allDisabled;
702       $('remove-host').disabled = allDisabled;
703       $('add-host').disabled = allDisabled;
704       $('proxy-all-protocols').disabled = allDisabled;
705       $('proxy-host-name').disabled = allDisabled;
706       $('proxy-host-port').disabled = allDisabled;
707       $('proxy-host-single-name').disabled = allDisabled;
708       $('proxy-host-single-port').disabled = allDisabled;
709       $('secure-proxy-host-name').disabled = allDisabled;
710       $('secure-proxy-port').disabled = allDisabled;
711       $('ftp-proxy').disabled = allDisabled;
712       $('ftp-proxy-port').disabled = allDisabled;
713       $('socks-host').disabled = allDisabled;
714       $('socks-port').disabled = allDisabled;
715       $('proxy-use-pac-url').disabled = true;
716       $('proxy-pac-url').disabled = true;
717       $('auto-proxy-parms').hidden = !$('auto-proxy').checked;
718       $('manual-proxy-parms').hidden = !$('manual-proxy').checked;
719       sendChromeMetricsAction('Options_NetworkManualProxy_Enable');
720     },
722     /**
723      * Helper method called from initializeDetailsPage and updateConnectionData.
724      * Updates visibility/enabled of the login/disconnect/configure buttons.
725      * @private
726      */
727     updateConnectionButtonVisibility_: function() {
728       var onc = this.onc_;
729       if (this.type_ == 'Ethernet') {
730         // Ethernet can never be connected or disconnected and can always be
731         // configured (e.g. to set security).
732         $('details-internet-login').hidden = true;
733         $('details-internet-disconnect').hidden = true;
734         $('details-internet-configure').hidden = false;
735         return;
736       }
738       var connectable = onc.getActiveValue('Connectable');
739       var connectState = onc.getActiveValue('ConnectionState');
740       if (connectState == 'NotConnected') {
741         $('details-internet-disconnect').hidden = true;
742         $('details-internet-login').hidden = false;
743         // Connecting to an unconfigured network might trigger certificate
744         // installation UI. Until that gets handled here, always enable the
745         // Connect button for built-in networks.
746         var enabled = (this.type_ != 'VPN') ||
747                       (onc.getActiveValue('VPN.Type') != 'ThirdPartyVPN') ||
748                       connectable;
749         $('details-internet-login').disabled = !enabled;
750       } else {
751         $('details-internet-login').hidden = true;
752         $('details-internet-disconnect').hidden = false;
753       }
755       var showConfigure = false;
756       if (this.type_ == 'VPN') {
757         showConfigure = true;
758       } else if (this.type_ == 'WiMAX' && connectState == 'NotConnected') {
759         showConfigure = true;
760       } else if (this.type_ == 'WiFi') {
761         showConfigure = (connectState == 'NotConnected' &&
762                          (!connectable || onc.getWiFiSecurity() != 'None'));
763       }
764       $('details-internet-configure').hidden = !showConfigure;
765     },
767     /**
768      * Helper method called from initializeDetailsPage and updateConnectionData.
769      * Updates the connection state property and account / sim card links.
770      * @private
771      */
772     updateDetails_: function() {
773       var onc = this.onc_;
775       var connectionStateString = onc.getTranslatedValue('ConnectionState');
776       $('connection-state').textContent = connectionStateString;
778       var type = this.type_;
779       var showViewAccount = false;
780       var showActivate = false;
781       if (type == 'WiFi') {
782         $('wifi-connection-state').textContent = connectionStateString;
783       } else if (type == 'WiMAX') {
784         $('wimax-connection-state').textContent = connectionStateString;
785       } else if (type == 'Cellular') {
786         $('activation-state').textContent =
787             onc.getTranslatedValue('Cellular.ActivationState');
788         if (onc.getActiveValue('Cellular.Family') == 'GSM') {
789           var lockEnabled =
790               onc.getActiveValue('Cellular.SIMLockStatus.LockEnabled');
791           $('sim-card-lock-enabled').checked = lockEnabled;
792           $('change-pin').hidden = !lockEnabled;
793         }
794         showViewAccount = shouldShowViewAccountButton(onc);
795         var activationState = onc.getActiveValue('Cellular.ActivationState');
796         showActivate = (activationState == 'NotActivated' ||
797                         activationState == 'PartiallyActivated');
798       }
800       $('view-account-details').hidden = !showViewAccount;
801       $('activate-details').hidden = !showActivate;
802       // If activation is not complete, hide the login button.
803       if (showActivate)
804         $('details-internet-login').hidden = true;
805     },
807     /**
808      * Helper method called from initializeDetailsPage and updateConnectionData.
809      * Updates the fields in the header section of the details frame.
810      * @private
811      */
812     populateHeader_: function() {
813       var onc = this.onc_;
815       var name = onc.getTranslatedValue('Name');
816       if (onc.getActiveValue('Type') == 'VPN' &&
817           onc.getActiveValue('VPN.Type') == 'ThirdPartyVPN') {
818         var providerName =
819             onc.getActiveValue('VPN.ThirdPartyVPN.ProviderName') ||
820             loadTimeData.getString('defaultThirdPartyProviderName');
821         name = loadTimeData.getStringF('vpnNameTemplate', providerName, name);
822       }
823       $('network-details-title').textContent = name;
825       var connectionStateString = onc.getTranslatedValue('ConnectionState');
826       $('network-details-subtitle-status').textContent = connectionStateString;
828       var typeKey;
829       var type = this.type_;
830       if (type == 'Ethernet')
831         typeKey = 'ethernetTitle';
832       else if (type == 'WiFi')
833         typeKey = 'wifiTitle';
834       else if (type == 'WiMAX')
835         typeKey = 'wimaxTitle';
836       else if (type == 'Cellular')
837         typeKey = 'cellularTitle';
838       else if (type == 'VPN')
839         typeKey = 'vpnTitle';
840       else
841         typeKey = null;
842       var typeLabel = $('network-details-subtitle-type');
843       var typeSeparator = $('network-details-subtitle-separator');
844       if (typeKey) {
845         typeLabel.textContent = loadTimeData.getString(typeKey);
846         typeLabel.hidden = false;
847         typeSeparator.hidden = false;
848       } else {
849         typeLabel.hidden = true;
850         typeSeparator.hidden = true;
851       }
852     },
854     /**
855      * Helper method to insert a 'user' option into the Apn list.
856      * @param {Object} userOption The 'user' apn dictionary
857      * @private
858      */
859     insertApnUserOption_: function(userOption) {
860       // Add the 'user' option before the last option ('other')
861       var apnSelector = $('select-apn');
862       assert(apnSelector.length > 0);
863       var otherOption = apnSelector[apnSelector.length - 1];
864       apnSelector.add(userOption, otherOption);
865       this.userApnIndex_ = apnSelector.length - 2;
866       this.selectedApnIndex_ = this.userApnIndex_;
867     },
869     /**
870      * Helper method called from initializeApnList to populate the Apn list.
871      * @param {Array} apnList List of available APNs.
872      * @private
873      */
874     populateApnList_: function(apnList) {
875       var onc = this.onc_;
876       var apnSelector = $('select-apn');
877       assert(apnSelector.length == 1);
878       var otherOption = apnSelector[0];
879       var activeApn = onc.getActiveValue('Cellular.APN.AccessPointName');
880       var lastGoodApn =
881           onc.getActiveValue('Cellular.LastGoodAPN.AccessPointName');
882       for (var i = 0; i < apnList.length; i++) {
883         var apnDict = apnList[i];
884         var localizedName = apnDict['LocalizedName'];
885         var name = localizedName ? localizedName : apnDict['Name'];
886         var accessPointName = apnDict['AccessPointName'];
887         var option = document.createElement('option');
888         option.textContent =
889             name ? (name + ' (' + accessPointName + ')') : accessPointName;
890         option.value = i;
891         // Insert new option before 'other' option.
892         apnSelector.add(option, otherOption);
893         if (this.selectedApnIndex_ != -1)
894           continue;
895         // If this matches the active Apn name, or LastGoodApn name (or there
896         // is no last good APN), set it as the selected Apn.
897         if ((activeApn == accessPointName) ||
898             (!activeApn && (!lastGoodApn || lastGoodApn == accessPointName))) {
899           this.selectedApnIndex_ = i;
900         }
901       }
902       if (this.selectedApnIndex_ == -1 && activeApn) {
903         this.userApn_ = activeApn;
904         // Create a 'user' entry for any active apn not in the list.
905         var userOption = document.createElement('option');
906         userOption.textContent = activeApn;
907         userOption.value = -1;
908         this.insertApnUserOption_(userOption);
909       }
910     },
912     /**
913      * Helper method called from initializeDetailsPage to initialize the Apn
914      * list.
915      * @private
916      */
917     initializeApnList_: function() {
918       this.selectedApnIndex_ = -1;
919       this.userApnIndex_ = -1;
921       var onc = this.onc_;
922       var apnSelector = $('select-apn');
924       // Clear APN lists, keep only last element, 'other'.
925       while (apnSelector.length != 1)
926         apnSelector.remove(0);
928       var apnList = onc.getActiveValue('Cellular.APNList');
929       if (apnList) {
930         // Populate the list with the existing APNs.
931         this.populateApnList_(apnList);
932       } else {
933         // Create a single 'default' entry.
934         var otherOption = apnSelector[0];
935         var defaultOption = document.createElement('option');
936         defaultOption.textContent =
937             loadTimeData.getString('cellularApnUseDefault');
938         defaultOption.value = -1;
939         // Add 'default' entry before 'other' option
940         apnSelector.add(defaultOption, otherOption);
941         assert(apnSelector.length == 2);  // 'default', 'other'
942         this.selectedApnIndex_ = 0;  // Select 'default'
943       }
944       assert(this.selectedApnIndex_ >= 0);
945       apnSelector.selectedIndex = this.selectedApnIndex_;
946       updateHidden('.apn-list-view', false);
947       updateHidden('.apn-details-view', true);
948     },
950     /**
951      * Helper function for setting APN properties.
952      * @param {Object} apnValue Dictionary of APN properties.
953      * @private
954      */
955     setActiveApn_: function(apnValue) {
956       var activeApn = {};
957       var apnName = apnValue['AccessPointName'];
958       if (apnName) {
959         activeApn['AccessPointName'] = apnName;
960         activeApn['Username'] = stringFromValue(apnValue['Username']);
961         activeApn['Password'] = stringFromValue(apnValue['Password']);
962       }
963       // Set the cached ONC data.
964       this.onc_.setProperty('Cellular.APN', activeApn);
965       // Set an ONC object with just the APN values.
966       var oncData = new OncData({});
967       oncData.setProperty('Cellular.APN', activeApn);
968       chrome.networkingPrivate.setProperties(this.onc_.guid(),
969                                              oncData.getData());
970     },
972     /**
973      * Event Listener for the cellular-apn-use-default button.
974      * @private
975      */
976     setDefaultApn_: function() {
977       var apnSelector = $('select-apn');
979       // Remove the 'user' entry if it exists.
980       if (this.userApnIndex_ != -1) {
981         assert(this.userApnIndex_ < apnSelector.length - 1);
982         apnSelector.remove(this.userApnIndex_);
983         this.userApnIndex_ = -1;
984       }
986       var apnList = this.onc_.getActiveValue('Cellular.APNList');
987       var iApn = (apnList != undefined && apnList.length > 0) ? 0 : -1;
988       apnSelector.selectedIndex = iApn;
989       this.selectedApnIndex_ = iApn;
991       // Clear any user APN entry to inform Chrome to use the default APN.
992       this.setActiveApn_({});
994       updateHidden('.apn-list-view', false);
995       updateHidden('.apn-details-view', true);
996     },
998     /**
999      * Event Listener for the cellular-apn-set button.
1000      * @private
1001      */
1002     setApn_: function(apnValue) {
1003       if (apnValue == '')
1004         return;
1006       var apnSelector = $('select-apn');
1008       var activeApn = {};
1009       activeApn['AccessPointName'] = stringFromValue(apnValue);
1010       activeApn['Username'] = stringFromValue($('cellular-apn-username').value);
1011       activeApn['Password'] = stringFromValue($('cellular-apn-password').value);
1012       this.setActiveApn_(activeApn);
1013       // Set the user selected APN.
1014       this.userApn_ = activeApn;
1016       // Remove any existing 'user' entry.
1017       if (this.userApnIndex_ != -1) {
1018         assert(this.userApnIndex_ < apnSelector.length - 1);
1019         apnSelector.remove(this.userApnIndex_);
1020         this.userApnIndex_ = -1;
1021       }
1023       // Create a new 'user' entry with the new active apn.
1024       var option = document.createElement('option');
1025       option.textContent = activeApn['AccessPointName'];
1026       option.value = -1;
1027       option.selected = true;
1028       this.insertApnUserOption_(option);
1030       updateHidden('.apn-list-view', false);
1031       updateHidden('.apn-details-view', true);
1032     },
1034     /**
1035      * Event Listener for the cellular-apn-cancel button.
1036      * @private
1037      */
1038     cancelApn_: function() { this.initializeApnList_(); },
1040     /**
1041      * Event Listener for the select-apn button.
1042      * @private
1043      */
1044     selectApn_: function() {
1045       var onc = this.onc_;
1046       var apnSelector = $('select-apn');
1047       if (apnSelector[apnSelector.selectedIndex].value != -1) {
1048         var apnList = onc.getActiveValue('Cellular.APNList');
1049         var apnIndex = apnSelector.selectedIndex;
1050         assert(apnIndex < apnList.length);
1051         this.selectedApnIndex_ = apnIndex;
1052         this.setActiveApn_(apnList[apnIndex]);
1053       } else if (apnSelector.selectedIndex == this.userApnIndex_) {
1054         this.selectedApnIndex_ = apnSelector.selectedIndex;
1055         this.setActiveApn_(this.userApn_);
1056       } else { // 'Other'
1057         var apnDict;
1058         if (this.userApn_['AccessPointName']) {
1059           // Fill in the details fields with the existing 'user' config.
1060           apnDict = this.userApn_;
1061         } else {
1062           // No 'user' config, use the current values.
1063           apnDict = {};
1064           apnDict['AccessPointName'] =
1065               onc.getActiveValue('Cellular.APN.AccessPointName');
1066           apnDict['Username'] = onc.getActiveValue('Cellular.APN.Username');
1067           apnDict['Password'] = onc.getActiveValue('Cellular.APN.Password');
1068         }
1069         $('cellular-apn').value = stringFromValue(apnDict['AccessPointName']);
1070         $('cellular-apn-username').value = stringFromValue(apnDict['Username']);
1071         $('cellular-apn-password').value = stringFromValue(apnDict['Password']);
1072         updateHidden('.apn-list-view', true);
1073         updateHidden('.apn-details-view', false);
1074       }
1075     }
1076   };
1078   /**
1079    * Enables or Disables all buttons that provide operations on the cellular
1080    * network.
1081    */
1082   DetailsInternetPage.changeCellularButtonsState = function(disable) {
1083     var buttonsToDisableList =
1084         new Array('details-internet-login',
1085                   'details-internet-disconnect',
1086                   'details-internet-configure',
1087                   'activate-details',
1088                   'view-account-details');
1090     for (var i = 0; i < buttonsToDisableList.length; ++i) {
1091       var button = $(buttonsToDisableList[i]);
1092       button.disabled = disable;
1093     }
1094   };
1096   /**
1097    * If the network is not already activated, starts the activation process or
1098    * shows the activation UI. Otherwise does nothing.
1099    */
1100   DetailsInternetPage.activateCellular = function(guid) {
1101     chrome.networkingPrivate.getProperties(guid, function(properties) {
1102       var oncData = new OncData(properties);
1103       if (oncData.getActiveValue('Cellular.ActivationState') == 'Activated') {
1104         return;
1105       }
1106       var carrier = oncData.getActiveValue('Cellular.Carrier');
1107       if (carrier == CarrierSprint) {
1108         // Sprint is directly ativated, call startActivate().
1109         chrome.networkingPrivate.startActivate(guid, '');
1110       } else {
1111         chrome.send('showMorePlanInfo', [guid]);
1112       }
1113     });
1114   };
1116   /**
1117    * Performs minimal initialization of the InternetDetails dialog in
1118    * preparation for showing proxy-settings.
1119    */
1120   DetailsInternetPage.initializeProxySettings = function() {
1121     DetailsInternetPage.getInstance().initializePageContents_();
1122   };
1124   /**
1125    * Displays the InternetDetails dialog with only the proxy settings visible.
1126    */
1127   DetailsInternetPage.showProxySettings = function() {
1128     var detailsPage = DetailsInternetPage.getInstance();
1129     $('network-details-header').hidden = true;
1130     $('activate-details').hidden = true;
1131     $('view-account-details').hidden = true;
1132     $('web-proxy-auto-discovery').hidden = true;
1133     detailsPage.showProxy_ = true;
1134     updateHidden('#internet-tab', true);
1135     updateHidden('#details-tab-strip', true);
1136     updateHidden('#details-internet-page .action-area', true);
1137     detailsPage.updateControls();
1138     detailsPage.visible = true;
1139     sendChromeMetricsAction('Options_NetworkShowProxyTab');
1140   };
1142   /**
1143    * Initializes even handling for keyboard driven flow.
1144    */
1145   DetailsInternetPage.initializeKeyboardFlow = function() {
1146     keyboard.initializeKeyboardFlow();
1147   };
1149   DetailsInternetPage.updateProxySettings = function(type) {
1150       var proxyHost = null,
1151           proxyPort = null;
1153       if (type == 'cros.session.proxy.singlehttp') {
1154         proxyHost = 'proxy-host-single-name';
1155         proxyPort = 'proxy-host-single-port';
1156       } else if (type == 'cros.session.proxy.httpurl') {
1157         proxyHost = 'proxy-host-name';
1158         proxyPort = 'proxy-host-port';
1159       } else if (type == 'cros.session.proxy.httpsurl') {
1160         proxyHost = 'secure-proxy-host-name';
1161         proxyPort = 'secure-proxy-port';
1162       } else if (type == 'cros.session.proxy.ftpurl') {
1163         proxyHost = 'ftp-proxy';
1164         proxyPort = 'ftp-proxy-port';
1165       } else if (type == 'cros.session.proxy.socks') {
1166         proxyHost = 'socks-host';
1167         proxyPort = 'socks-port';
1168       } else {
1169         return;
1170       }
1172       var hostValue = $(proxyHost).value;
1173       if (hostValue.indexOf(':') !== -1) {
1174         if (hostValue.match(/:/g).length == 1) {
1175           hostValue = hostValue.split(':');
1176           $(proxyHost).value = hostValue[0];
1177           $(proxyPort).value = hostValue[1];
1178         }
1179       }
1180   };
1182   DetailsInternetPage.loginFromDetails = function() {
1183     DetailsInternetPage.configureOrConnect();
1184     PageManager.closeOverlay();
1185   };
1187   /**
1188    * This function identifies unconfigured networks and networks that are
1189    * likely to fail (e.g. due to a bad passphrase on a previous connect
1190    * attempt). For such networks a configure dialog will be opened. Otherwise
1191    * a connection will be attempted.
1192    */
1193   DetailsInternetPage.configureOrConnect = function() {
1194     var detailsPage = DetailsInternetPage.getInstance();
1195     if (detailsPage.type_ == 'WiFi')
1196       sendChromeMetricsAction('Options_NetworkConnectToWifi');
1197     else if (detailsPage.type_ == 'VPN')
1198       sendChromeMetricsAction('Options_NetworkConnectToVPN');
1200     var onc = detailsPage.onc_;
1201     var guid = onc.guid();
1202     var type = onc.getActiveValue('Type');
1204     // Built-in VPNs do not correctly set 'Connectable', so we always show the
1205     // configuration UI.
1206     if (type == 'VPN') {
1207       if (onc.getActiveValue('VPN.Type') != 'ThirdPartyVPN') {
1208         chrome.send('configureNetwork', [guid]);
1209         return;
1210       }
1211     }
1213     // If 'Connectable' is false for WiFi or WiMAX, Shill requires
1214     // additional configuration to connect, so show the configuration UI.
1215     if ((type == 'WiFi' || type == 'WiMAX') &&
1216         !onc.getActiveValue('Connectable')) {
1217       chrome.send('configureNetwork', [guid]);
1218       return;
1219     }
1221     // Secure WiFi networks with ErrorState set most likely require
1222     // configuration (e.g. a correct passphrase) before connecting.
1223     if (type == 'WiFi' && onc.getWiFiSecurity() != 'None') {
1224       var errorState = onc.getActiveValue('ErrorState');
1225       if (errorState && errorState != 'Unknown') {
1226         chrome.send('configureNetwork', [guid]);
1227         return;
1228       }
1229     }
1231     // Cellular networks need to be activated before they can be connected to.
1232     if (type == 'Cellular') {
1233       var activationState = onc.getActiveValue('Cellular.ActivationState');
1234       if (activationState != 'Activated' && activationState != 'Unknown') {
1235         DetailsInternetPage.activateCellular(guid);
1236         return;
1237       }
1238     }
1240     chrome.networkingPrivate.startConnect(guid);
1241   };
1243   DetailsInternetPage.disconnectNetwork = function() {
1244     var detailsPage = DetailsInternetPage.getInstance();
1245     if (detailsPage.type_ == 'WiFi')
1246       sendChromeMetricsAction('Options_NetworkDisconnectWifi');
1247     else if (detailsPage.type_ == 'VPN')
1248       sendChromeMetricsAction('Options_NetworkDisconnectVPN');
1249     chrome.networkingPrivate.startDisconnect(detailsPage.onc_.guid());
1250     PageManager.closeOverlay();
1251   };
1253   DetailsInternetPage.configureNetwork = function() {
1254     var detailsPage = DetailsInternetPage.getInstance();
1255     // This is an explicit request to show the configure dialog; do not show
1256     // the enrollment dialog for networks missing a certificate.
1257     var forceShow = true;
1258     chrome.send('configureNetwork', [detailsPage.onc_.guid(), forceShow]);
1259     PageManager.closeOverlay();
1260   };
1262   DetailsInternetPage.activateFromDetails = function() {
1263     var detailsPage = DetailsInternetPage.getInstance();
1264     if (detailsPage.type_ == 'Cellular')
1265       DetailsInternetPage.activateCellular(detailsPage.onc_.guid());
1266     PageManager.closeOverlay();
1267   };
1269   /**
1270    * Event handler called when the details page is closed. Sends changed
1271    * properties to Chrome and closes the overlay.
1272    */
1273   DetailsInternetPage.setDetails = function() {
1274     var detailsPage = DetailsInternetPage.getInstance();
1275     var type = detailsPage.type_;
1276     var oncData = new OncData({});
1277     var autoConnectCheckboxId = '';
1278     if (type == 'WiFi') {
1279       var preferredCheckbox =
1280           assertInstanceof($('prefer-network-wifi'), HTMLInputElement);
1281       if (!preferredCheckbox.hidden && !preferredCheckbox.disabled) {
1282         var kPreferredPriority = 1;
1283         var priority = preferredCheckbox.checked ? kPreferredPriority : 0;
1284         oncData.setProperty('Priority', priority);
1285         sendChromeMetricsAction('Options_NetworkSetPrefer');
1286       }
1287       autoConnectCheckboxId = 'auto-connect-network-wifi';
1288     } else if (type == 'WiMAX') {
1289       autoConnectCheckboxId = 'auto-connect-network-wimax';
1290     } else if (type == 'Cellular') {
1291       autoConnectCheckboxId = 'auto-connect-network-cellular';
1292     } else if (type == 'VPN') {
1293       var providerType = detailsPage.onc_.getActiveValue('VPN.Type');
1294       if (providerType != 'ThirdPartyVPN') {
1295         oncData.setProperty('VPN.Type', providerType);
1296         oncData.setProperty('VPN.Host', $('inet-server-hostname').value);
1297         autoConnectCheckboxId = 'auto-connect-network-vpn';
1298       }
1299     }
1300     if (autoConnectCheckboxId != '') {
1301       var autoConnectCheckbox =
1302           assertInstanceof($(autoConnectCheckboxId), HTMLInputElement);
1303       if (!autoConnectCheckbox.hidden && !autoConnectCheckbox.disabled) {
1304         var autoConnectKey = type + '.AutoConnect';
1305         oncData.setProperty(autoConnectKey, !!autoConnectCheckbox.checked);
1306         sendChromeMetricsAction('Options_NetworkAutoConnect');
1307       }
1308     }
1310     var nameServerTypes = ['automatic', 'google', 'user'];
1311     var nameServerType = 'automatic';
1312     for (var i = 0; i < nameServerTypes.length; ++i) {
1313       if ($(nameServerTypes[i] + '-dns-radio').checked) {
1314         nameServerType = nameServerTypes[i];
1315         break;
1316       }
1317     }
1318     var ipConfig = detailsPage.getIpConfig_(nameServerType);
1319     var ipAddressType = ('IPAddress' in ipConfig) ? 'Static' : 'DHCP';
1320     var nameServersType = ('NameServers' in ipConfig) ? 'Static' : 'DHCP';
1321     oncData.setProperty('IPAddressConfigType', ipAddressType);
1322     oncData.setProperty('NameServersConfigType', nameServersType);
1323     oncData.setProperty('StaticIPConfig', ipConfig);
1325     var data = oncData.getData();
1326     if (Object.keys(data).length > 0) {
1327       // TODO(stevenjb): Only set changed properties.
1328       chrome.networkingPrivate.setProperties(detailsPage.onc_.guid(), data);
1329     }
1331     PageManager.closeOverlay();
1332   };
1334   /**
1335    * Event handler called when the name server type changes.
1336    * @param {string} type The selected name sever type, 'automatic', 'google',
1337    *                      or 'user'.
1338    */
1339   DetailsInternetPage.updateNameServerDisplay = function(type) {
1340     var editable = type == 'user';
1341     var fields = [$('ipconfig-dns1'), $('ipconfig-dns2'),
1342                   $('ipconfig-dns3'), $('ipconfig-dns4')];
1343     for (var i = 0; i < fields.length; ++i) {
1344       fields[i].editable = editable;
1345     }
1346     if (editable)
1347       $('ipconfig-dns1').focus();
1349     var automaticDns = $('automatic-dns-display');
1350     var googleDns = $('google-dns-display');
1351     var userDns = $('user-dns-settings');
1352     switch (type) {
1353       case 'automatic':
1354         automaticDns.setAttribute('selected', '');
1355         googleDns.removeAttribute('selected');
1356         userDns.removeAttribute('selected');
1357         break;
1358       case 'google':
1359         automaticDns.removeAttribute('selected');
1360         googleDns.setAttribute('selected', '');
1361         userDns.removeAttribute('selected');
1362         break;
1363       case 'user':
1364         automaticDns.removeAttribute('selected');
1365         googleDns.removeAttribute('selected');
1366         userDns.setAttribute('selected', '');
1367         break;
1368     }
1369   };
1371   /**
1372    * Method called from Chrome when the ONC properties for the displayed
1373    * network may have changed.
1374    * @param {Object} oncData The updated ONC dictionary for the network.
1375    */
1376   DetailsInternetPage.updateConnectionData = function(oncData) {
1377     var detailsPage = DetailsInternetPage.getInstance();
1378     if (!detailsPage.visible)
1379       return;
1381     if (oncData.GUID != detailsPage.onc_.guid())
1382       return;
1384     // Update our cached data object.
1385     detailsPage.onc_ = new OncData(oncData);
1387     detailsPage.populateHeader_();
1388     detailsPage.updateConnectionButtonVisibility_();
1389     detailsPage.updateDetails_();
1390   };
1392   /**
1393    * Initializes the details page with the provided ONC data.
1394    * @param {Object} oncData Dictionary of ONC properties.
1395    */
1396   DetailsInternetPage.initializeDetailsPage = function(oncData) {
1397     var onc = new OncData(oncData);
1399     var detailsPage = DetailsInternetPage.getInstance();
1400     detailsPage.onc_ = onc;
1401     var type = onc.getActiveValue('Type');
1402     detailsPage.type_ = type;
1404     sendShowDetailsMetrics(type, onc.getActiveValue('ConnectionState'));
1406     detailsPage.populateHeader_();
1407     detailsPage.updateConnectionButtonVisibility_();
1408     detailsPage.updateDetails_();
1410     // TODO(stevenjb): Some of the setup below should be moved to
1411     // updateDetails_() so that updates are reflected in the UI.
1413     // Only show proxy for remembered networks.
1414     var remembered = onc.getSource() != 'None';
1415     if (remembered) {
1416       detailsPage.showProxy_ = true;
1417       // Inform Chrome which network to use for proxy configuration.
1418       chrome.send('selectNetwork', [detailsPage.onc_.guid()]);
1419     } else {
1420       detailsPage.showProxy_ = false;
1421     }
1423     $('web-proxy-auto-discovery').hidden = true;
1425     var restricted = onc.getActiveValue('RestrictedConnectivity');
1426     var restrictedString = loadTimeData.getString(
1427         restricted ? 'restrictedYes' : 'restrictedNo');
1429     // These objects contain an 'automatic' property that is displayed when
1430     // ip-automatic-configuration-checkbox is checked, and a 'value' property
1431     // that is displayed when unchecked and used to set the associated ONC
1432     // property for StaticIPConfig on commit.
1433     var inetAddress = {};
1434     var inetNetmask = {};
1435     var inetGateway = {};
1437     var inetNameServersString;
1439     var ipconfigList = onc.getActiveValue('IPConfigs');
1440     if (Array.isArray(ipconfigList)) {
1441       for (var i = 0; i < ipconfigList.length; ++i) {
1442         var ipconfig = ipconfigList[i];
1443         var ipType = ipconfig['Type'];
1444         if (ipType != 'IPv4') {
1445           // TODO(stevenjb): Handle IPv6 properties.
1446           continue;
1447         }
1448         var address = ipconfig['IPAddress'];
1449         inetAddress.automatic = address;
1450         inetAddress.value = address;
1451         var netmask = prefixLengthToNetmask(ipconfig['RoutingPrefix']);
1452         inetNetmask.automatic = netmask;
1453         inetNetmask.value = netmask;
1454         var gateway = ipconfig['Gateway'];
1455         inetGateway.automatic = gateway;
1456         inetGateway.value = gateway;
1457         if ('WebProxyAutoDiscoveryUrl' in ipconfig) {
1458           $('web-proxy-auto-discovery').hidden = false;
1459           $('web-proxy-auto-discovery-url').value =
1460               ipconfig['WebProxyAutoDiscoveryUrl'];
1461         }
1462         if ('NameServers' in ipconfig) {
1463           var inetNameServers = ipconfig['NameServers'];
1464           inetNameServers = inetNameServers.sort();
1465           inetNameServersString = inetNameServers.join(',');
1466         }
1467         break;  // Use the first IPv4 entry.
1468       }
1469     }
1471     // Override the 'automatic' properties with the saved DHCP values if the
1472     // saved value is set, and set any unset 'value' properties.
1473     var savedNameServersString;
1474     var savedIpAddress = onc.getActiveValue('SavedIPConfig.IPAddress');
1475     if (savedIpAddress != undefined) {
1476       inetAddress.automatic = savedIpAddress;
1477       if (!inetAddress.value)
1478         inetAddress.value = savedIpAddress;
1479     }
1480     var savedPrefix = onc.getActiveValue('SavedIPConfig.RoutingPrefix');
1481     if (savedPrefix != undefined) {
1482       assert(typeof savedPrefix == 'number');
1483       var savedNetmask = prefixLengthToNetmask(
1484           /** @type {number} */(savedPrefix));
1485       inetNetmask.automatic = savedNetmask;
1486       if (!inetNetmask.value)
1487         inetNetmask.value = savedNetmask;
1488     }
1489     var savedGateway = onc.getActiveValue('SavedIPConfig.Gateway');
1490     if (savedGateway != undefined) {
1491       inetGateway.automatic = savedGateway;
1492       if (!inetGateway.value)
1493         inetGateway.value = savedGateway;
1494     }
1496     var savedNameServers = onc.getActiveValue('SavedIPConfig.NameServers');
1497     if (savedNameServers) {
1498       savedNameServers = savedNameServers.sort();
1499       savedNameServersString = savedNameServers.join(',');
1500     }
1502     var ipAutoConfig = 'automatic';
1503     if (onc.getActiveValue('IPAddressConfigType') == 'Static') {
1504       ipAutoConfig = 'user';
1505       var staticIpAddress = onc.getActiveValue('StaticIPConfig.IPAddress');
1506       inetAddress.user = staticIpAddress;
1507       inetAddress.value = staticIpAddress;
1509       var staticPrefix = onc.getActiveValue('StaticIPConfig.RoutingPrefix');
1510       if (typeof staticPrefix != 'number')
1511         staticPrefix = 0;
1512       var staticNetmask = prefixLengthToNetmask(
1513           /** @type {number} */ (staticPrefix));
1514       inetNetmask.user = staticNetmask;
1515       inetNetmask.value = staticNetmask;
1517       var staticGateway = onc.getActiveValue('StaticIPConfig.Gateway');
1518       inetGateway.user = staticGateway;
1519       inetGateway.value = staticGateway;
1520     }
1522     var staticNameServersString;
1523     if (onc.getActiveValue('NameServersConfigType') == 'Static') {
1524       var staticNameServers = onc.getActiveValue('StaticIPConfig.NameServers');
1525       staticNameServers = staticNameServers.sort();
1526       staticNameServersString = staticNameServers.join(',');
1527     }
1529     $('ip-automatic-configuration-checkbox').checked =
1530         ipAutoConfig == 'automatic';
1532     inetAddress.autoConfig = ipAutoConfig;
1533     inetNetmask.autoConfig = ipAutoConfig;
1534     inetGateway.autoConfig = ipAutoConfig;
1536     var configureAddressField = function(field, model) {
1537       IPAddressField.decorate(field);
1538       field.model = model;
1539       field.editable = model.autoConfig == 'user';
1540     };
1541     configureAddressField($('ip-address'), inetAddress);
1542     configureAddressField($('ip-netmask'), inetNetmask);
1543     configureAddressField($('ip-gateway'), inetGateway);
1545     // Set Nameserver fields. Nameservers are 'automatic' by default. If a
1546     // static namerserver is set, use that unless it does not match a non
1547     // empty 'NameServers' value (indicating that the custom nameservers are
1548     // invalid or not being applied for some reason). TODO(stevenjb): Only
1549     // set these properites if they change so that invalid custom values do
1550     // not get lost.
1551     var nameServerType = 'automatic';
1552     if (staticNameServersString &&
1553         (!inetNameServersString ||
1554          staticNameServersString == inetNameServersString)) {
1555       if (staticNameServersString == GoogleNameServers.join(','))
1556         nameServerType = 'google';
1557       else
1558         nameServerType = 'user';
1559     }
1560     if (nameServerType == 'automatic')
1561       $('automatic-dns-display').textContent = inetNameServersString;
1562     else
1563       $('automatic-dns-display').textContent = savedNameServersString;
1564     $('google-dns-display').textContent = GoogleNameServers.join(',');
1566     var nameServersUser = [];
1567     if (staticNameServers) {
1568       nameServersUser = staticNameServers;
1569     } else if (savedNameServers) {
1570       // Pre-populate with values provided by DHCP server.
1571       nameServersUser = savedNameServers;
1572     }
1574     var nameServerModels = [];
1575     for (var i = 0; i < 4; ++i)
1576       nameServerModels.push({value: nameServersUser[i] || ''});
1578     $(nameServerType + '-dns-radio').checked = true;
1579     configureAddressField($('ipconfig-dns1'), nameServerModels[0]);
1580     configureAddressField($('ipconfig-dns2'), nameServerModels[1]);
1581     configureAddressField($('ipconfig-dns3'), nameServerModels[2]);
1582     configureAddressField($('ipconfig-dns4'), nameServerModels[3]);
1584     DetailsInternetPage.updateNameServerDisplay(nameServerType);
1586     var macAddress = onc.getActiveValue('MacAddress');
1587     if (macAddress) {
1588       $('hardware-address').textContent = macAddress;
1589       $('hardware-address-row').style.display = 'table-row';
1590     } else {
1591       // This is most likely a device without a hardware address.
1592       $('hardware-address-row').style.display = 'none';
1593     }
1595     var setOrHideParent = function(field, property) {
1596       if (property != undefined) {
1597         $(field).textContent = property;
1598         $(field).parentElement.hidden = false;
1599       } else {
1600         $(field).parentElement.hidden = true;
1601       }
1602     };
1604     var networkName = onc.getTranslatedValue('Name');
1606     // Signal strength as percentage (for WiFi and WiMAX).
1607     var signalStrength;
1608     if (type == 'WiFi' || type == 'WiMAX')
1609       signalStrength = onc.getActiveValue(type + '.SignalStrength');
1610     if (!signalStrength)
1611       signalStrength = 0;
1612     var strengthFormat = loadTimeData.getString('inetSignalStrengthFormat');
1613     var strengthString = strengthFormat.replace('$1', signalStrength);
1615     if (type == 'WiFi') {
1616       OptionsPage.showTab($('wifi-network-nav-tab'));
1617       $('wifi-restricted-connectivity').textContent = restrictedString;
1618       var ssid = onc.getActiveValue('WiFi.SSID');
1619       $('wifi-ssid').textContent = ssid ? ssid : networkName;
1620       setOrHideParent('wifi-bssid', onc.getActiveValue('WiFi.BSSID'));
1621       var security = onc.getWiFiSecurity();
1622       if (security == 'None')
1623         security = undefined;
1624       setOrHideParent('wifi-security', security);
1625       // Frequency is in MHz.
1626       var frequency = onc.getActiveValue('WiFi.Frequency');
1627       if (!frequency)
1628         frequency = 0;
1629       var frequencyFormat = loadTimeData.getString('inetFrequencyFormat');
1630       frequencyFormat = frequencyFormat.replace('$1', frequency);
1631       $('wifi-frequency').textContent = frequencyFormat;
1632       $('wifi-signal-strength').textContent = strengthString;
1633       setOrHideParent('wifi-hardware-address',
1634                       onc.getActiveValue('MacAddress'));
1635       var priority = onc.getActiveValue('Priority');
1636       $('prefer-network-wifi').checked = priority > 0;
1637       $('prefer-network-wifi').disabled = !remembered;
1638       $('auto-connect-network-wifi').checked =
1639           onc.getActiveValue('WiFi.AutoConnect');
1640       $('auto-connect-network-wifi').disabled = !remembered;
1641     } else if (type == 'WiMAX') {
1642       OptionsPage.showTab($('wimax-network-nav-tab'));
1643       $('wimax-restricted-connectivity').textContent = restrictedString;
1645       $('auto-connect-network-wimax').checked =
1646           onc.getActiveValue('WiMAX.AutoConnect');
1647       $('auto-connect-network-wimax').disabled = !remembered;
1648       var identity = onc.getActiveValue('WiMAX.EAP.Identity');
1649       setOrHideParent('wimax-eap-identity', identity);
1650       $('wimax-signal-strength').textContent = strengthString;
1651     } else if (type == 'Cellular') {
1652       OptionsPage.showTab($('cellular-conn-nav-tab'));
1654       var isGsm = onc.getActiveValue('Cellular.Family') == 'GSM';
1656       $('service-name').textContent = networkName;
1658       // TODO(stevenjb): Ideally many of these should be localized.
1659       $('network-technology').textContent =
1660           onc.getActiveValue('Cellular.NetworkTechnology');
1661       $('roaming-state').textContent =
1662           onc.getTranslatedValue('Cellular.RoamingState');
1663       $('cellular-restricted-connectivity').textContent = restrictedString;
1664       $('error-state').textContent = onc.getActiveValue('ErrorState');
1665       $('manufacturer').textContent =
1666           onc.getActiveValue('Cellular.Manufacturer');
1667       $('model-id').textContent = onc.getActiveValue('Cellular.ModelID');
1668       $('firmware-revision').textContent =
1669           onc.getActiveValue('Cellular.FirmwareRevision');
1670       $('hardware-revision').textContent =
1671           onc.getActiveValue('Cellular.HardwareRevision');
1672       $('mdn').textContent = onc.getActiveValue('Cellular.MDN');
1674       // Show ServingOperator properties only if available.
1675       var servingOperatorName =
1676           onc.getActiveValue('Cellular.ServingOperator.Name');
1677       var servingOperatorCode =
1678           onc.getActiveValue('Cellular.ServingOperator.Code');
1679       if (servingOperatorName != undefined &&
1680           servingOperatorCode != undefined) {
1681         $('operator-name').textContent = servingOperatorName;
1682         $('operator-code').textContent = servingOperatorCode;
1683       } else {
1684         $('operator-name').parentElement.hidden = true;
1685         $('operator-code').parentElement.hidden = true;
1686       }
1687       // Make sure that GSM/CDMA specific properties that shouldn't be hidden
1688       // are visible.
1689       updateHidden('#details-internet-page .gsm-only', false);
1690       updateHidden('#details-internet-page .cdma-only', false);
1692       // Show IMEI/ESN/MEID/MIN/PRL only if they are available.
1693       setOrHideParent('esn', onc.getActiveValue('Cellular.ESN'));
1694       setOrHideParent('imei', onc.getActiveValue('Cellular.IMEI'));
1695       setOrHideParent('meid', onc.getActiveValue('Cellular.MEID'));
1696       setOrHideParent('min', onc.getActiveValue('Cellular.MIN'));
1697       setOrHideParent('prl-version', onc.getActiveValue('Cellular.PRLVersion'));
1699       if (isGsm) {
1700         $('iccid').textContent = onc.getActiveValue('Cellular.ICCID');
1701         $('imsi').textContent = onc.getActiveValue('Cellular.IMSI');
1702         detailsPage.initializeApnList_();
1703       }
1704       $('auto-connect-network-cellular').checked =
1705           onc.getActiveValue('Cellular.AutoConnect');
1706       $('auto-connect-network-cellular').disabled = false;
1707     } else if (type == 'VPN') {
1708       OptionsPage.showTab($('vpn-nav-tab'));
1709       var providerType = onc.getActiveValue('VPN.Type');
1710       var isThirdPartyVPN = providerType == 'ThirdPartyVPN';
1711       $('vpn-tab').classList.toggle('third-party-vpn-provider',
1712                                     isThirdPartyVPN);
1714       $('inet-service-name').textContent = networkName;
1715       $('inet-provider-type').textContent =
1716           onc.getTranslatedValue('VPN.Type');
1718       if (isThirdPartyVPN) {
1719         $('inet-provider-name').textContent =
1720             onc.getActiveValue('VPN.ThirdPartyVPN.ProviderName');
1721       } else {
1722         var usernameKey;
1723         if (providerType == 'OpenVPN')
1724           usernameKey = 'VPN.OpenVPN.Username';
1725         else if (providerType == 'L2TP-IPsec')
1726           usernameKey = 'VPN.L2TP.Username';
1728         if (usernameKey) {
1729           $('inet-username').parentElement.hidden = false;
1730           $('inet-username').textContent = onc.getActiveValue(usernameKey);
1731         } else {
1732           $('inet-username').parentElement.hidden = true;
1733         }
1734         var inetServerHostname = $('inet-server-hostname');
1735         inetServerHostname.value = onc.getActiveValue('VPN.Host');
1736         inetServerHostname.resetHandler = function() {
1737           PageManager.hideBubble();
1738           var recommended = onc.getRecommendedValue('VPN.Host');
1739           if (recommended != undefined)
1740             inetServerHostname.value = recommended;
1741         };
1742         $('auto-connect-network-vpn').checked =
1743             onc.getActiveValue('VPN.AutoConnect');
1744         $('auto-connect-network-vpn').disabled = false;
1745       }
1746     } else {
1747       OptionsPage.showTab($('internet-nav-tab'));
1748     }
1750     // Update controlled option indicators.
1751     var indicators = cr.doc.querySelectorAll(
1752         '#details-internet-page .controlled-setting-indicator');
1753     for (var i = 0; i < indicators.length; i++) {
1754       var managed = indicators[i].hasAttribute('managed');
1755       // TODO(stevenjb): Eliminate support for 'data' once 39 is stable.
1756       var attributeName = managed ? 'managed' : 'data';
1757       var propName = indicators[i].getAttribute(attributeName);
1758       if (!propName)
1759         continue;
1760       var propValue = managed ?
1761           onc.getManagedProperty(propName) :
1762           onc.getActiveValue(propName);
1763       // If the property is unset or unmanaged (i.e. not an Object) skip it.
1764       if (propValue == undefined || (typeof propValue != 'object'))
1765         continue;
1766       var event;
1767       if (managed)
1768         event = detailsPage.createManagedEvent_(propName, propValue);
1769       else
1770         event = detailsPage.createControlledEvent_(propName,
1771             /** @type {{value: *, controlledBy: *, recommendedValue: *}} */(
1772                 propValue));
1773       indicators[i].handlePrefChange(event);
1774       var forElement = $(indicators[i].getAttribute('internet-detail-for'));
1775       if (forElement) {
1776         if (event.value.controlledBy == 'policy')
1777           forElement.disabled = true;
1778         if (forElement.resetHandler)
1779           indicators[i].resetHandler = forElement.resetHandler;
1780       }
1781     }
1783     detailsPage.updateControls();
1785     // Don't show page name in address bar and in history to prevent people
1786     // navigate here by hand and solve issue with page session restore.
1787     PageManager.showPageByName('detailsInternetPage', false);
1788   };
1790   return {
1791     DetailsInternetPage: DetailsInternetPage
1792   };