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 cr.define('options.internet', function() { 6 var OptionsPage = options.OptionsPage; 7 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; 8 /** @const */ var IPAddressField = options.internet.IPAddressField; 9 10 /** 11 * Network settings constants. These enums must match their C++ 12 * counterparts. 13 */ 14 function Constants() {} 15 16 // Network types: 17 Constants.TYPE_UNKNOWN = 'UNKNOWN'; 18 Constants.TYPE_ETHERNET = 'ethernet'; 19 Constants.TYPE_WIFI = 'wifi'; 20 Constants.TYPE_WIMAX = 'wimax'; 21 Constants.TYPE_BLUETOOTH = 'bluetooth'; 22 Constants.TYPE_CELLULAR = 'cellular'; 23 Constants.TYPE_VPN = 'vpn'; 24 25 /* 26 * Helper function to set hidden attribute for elements matching a selector. 27 * @param {string} selector CSS selector for extracting a list of elements. 28 * @param {bool} hidden New hidden value. 29 */ 30 function updateHidden(selector, hidden) { 31 var elements = cr.doc.querySelectorAll(selector); 32 for (var i = 0, el; el = elements[i]; i++) { 33 el.hidden = hidden; 34 } 35 } 36 37 /* 38 * Helper function to update the properties of the data object from the 39 * properties in the update object. 40 * @param {object} data object to update. 41 * @param {object} object containing the updated properties. 42 */ 43 function updateDataObject(data, update) { 44 for (prop in update) { 45 if (prop in data) 46 data[prop] = update[prop]; 47 } 48 } 49 50 /** 51 * Monitor pref change of given element. 52 * @param {Element} el Target element. 53 */ 54 function observePrefsUI(el) { 55 Preferences.getInstance().addEventListener(el.pref, handlePrefUpdate); 56 } 57 58 /** 59 * UI pref change handler. 60 * @param {Event} e The update event. 61 */ 62 function handlePrefUpdate(e) { 63 DetailsInternetPage.getInstance().updateControls(); 64 } 65 66 /** 67 * Simple helper method for converting a field to a string. It is used to 68 * easily assign an empty string from fields that may be unknown or undefined. 69 * @param {object} value that should be converted to a string. 70 * @return {string} the result. 71 */ 72 function stringFromValue(value) { 73 return value ? String(value) : ''; 74 } 75 76 /** 77 * Sends the 'checked' state of a control to chrome for a network. 78 * @param {string} path The service path of the network. 79 * @param {string} message The message to send to chrome. 80 * @param {HTMLInputElement} checkbox The checkbox storing the value to send. 81 */ 82 function sendCheckedIfEnabled(path, message, checkbox) { 83 if (!checkbox.hidden && !checkbox.disabled) 84 chrome.send(message, [path, checkbox.checked ? 'true' : 'false']); 85 } 86 87 ///////////////////////////////////////////////////////////////////////////// 88 // DetailsInternetPage class: 89 90 /** 91 * Encapsulated handling of ChromeOS internet details overlay page. 92 * @constructor 93 */ 94 function DetailsInternetPage() { 95 OptionsPage.call(this, 96 'detailsInternetPage', 97 null, 98 'details-internet-page'); 99 } 100 101 cr.addSingletonGetter(DetailsInternetPage); 102 103 DetailsInternetPage.prototype = { 104 __proto__: OptionsPage.prototype, 105 106 /** 107 * Initializes DetailsInternetPage page. 108 * Calls base class implementation to starts preference initialization. 109 */ 110 initializePage: function() { 111 OptionsPage.prototype.initializePage.call(this); 112 var params = parseQueryParams(window.location); 113 this.initializePageContents_(params); 114 this.showNetworkDetails_(params); 115 }, 116 117 /** 118 * Auto-activates the network details dialog if network information 119 * is included in the URL. 120 */ 121 showNetworkDetails_: function(params) { 122 var servicePath = params.servicePath; 123 if (!servicePath || !servicePath.length) 124 return; 125 var networkType = ''; // ignored for 'options' 126 chrome.send('networkCommand', [networkType, servicePath, 'options']); 127 }, 128 129 130 /** 131 * Initializes the contents of the page. 132 */ 133 initializePageContents_: function(params) { 134 $('details-internet-dismiss').addEventListener('click', function(event) { 135 DetailsInternetPage.setDetails(); 136 }); 137 138 $('details-internet-login').addEventListener('click', function(event) { 139 DetailsInternetPage.setDetails(); 140 DetailsInternetPage.loginFromDetails(); 141 }); 142 143 $('details-internet-disconnect').addEventListener('click', 144 function(event) { 145 DetailsInternetPage.setDetails(); 146 DetailsInternetPage.disconnectNetwork(); 147 }); 148 149 $('details-internet-configure').addEventListener('click', 150 function(event) { 151 DetailsInternetPage.setDetails(); 152 DetailsInternetPage.configureNetwork(); 153 }); 154 155 $('activate-details').addEventListener('click', function(event) { 156 DetailsInternetPage.activateFromDetails(); 157 }); 158 159 $('buyplan-details').addEventListener('click', function(event) { 160 var data = $('connection-state').data; 161 chrome.send('buyDataPlan', [data.servicePath]); 162 OptionsPage.closeOverlay(); 163 }); 164 165 $('view-account-details').addEventListener('click', function(event) { 166 var data = $('connection-state').data; 167 chrome.send('showMorePlanInfo', [data.servicePath]); 168 OptionsPage.closeOverlay(); 169 }); 170 171 $('cellular-apn-use-default').addEventListener('click', function(event) { 172 var data = $('connection-state').data; 173 var apnSelector = $('select-apn'); 174 175 if (data.userApnIndex != -1) { 176 apnSelector.remove(data.userApnIndex); 177 data.userApnIndex = -1; 178 } 179 180 if (data.providerApnList.value.length > 0) { 181 var iApn = 0; 182 var defaultApn = data.providerApnList.value[iApn]; 183 data.apn.apn = stringFromValue(defaultApn.apn); 184 data.apn.username = stringFromValue(defaultApn.username); 185 data.apn.password = stringFromValue(defaultApn.password); 186 chrome.send('setApn', [data.servicePath, 187 data.apn.apn, 188 data.apn.username, 189 data.apn.password]); 190 apnSelector.selectedIndex = iApn; 191 data.selectedApn = iApn; 192 } else { 193 data.apn.apn = ''; 194 data.apn.username = ''; 195 data.apn.password = ''; 196 apnSelector.selectedIndex = -1; 197 data.selectedApn = -1; 198 } 199 updateHidden('.apn-list-view', false); 200 updateHidden('.apn-details-view', true); 201 }); 202 203 $('cellular-apn-set').addEventListener('click', function(event) { 204 if ($('cellular-apn').value == '') 205 return; 206 207 var data = $('connection-state').data; 208 var apnSelector = $('select-apn'); 209 210 data.apn.apn = stringFromValue($('cellular-apn').value); 211 data.apn.username = stringFromValue($('cellular-apn-username').value); 212 data.apn.password = stringFromValue($('cellular-apn-password').value); 213 data.userApn = { 214 'apn': data.apn.apn, 215 'username': data.apn.username, 216 'password': data.apn.password 217 }; 218 chrome.send('setApn', [data.servicePath, 219 data.apn.apn, 220 data.apn.username, 221 data.apn.password]); 222 223 if (data.userApnIndex != -1) { 224 apnSelector.remove(data.userApnIndex); 225 data.userApnIndex = -1; 226 } 227 228 var option = document.createElement('option'); 229 option.textContent = data.apn.apn; 230 option.value = -1; 231 option.selected = true; 232 apnSelector.add(option, apnSelector[apnSelector.length - 1]); 233 data.userApnIndex = apnSelector.length - 2; 234 data.selectedApn = data.userApnIndex; 235 236 updateHidden('.apn-list-view', false); 237 updateHidden('.apn-details-view', true); 238 }); 239 240 $('cellular-apn-cancel').addEventListener('click', function(event) { 241 $('select-apn').selectedIndex = $('connection-state').data.selectedApn; 242 updateHidden('.apn-list-view', false); 243 updateHidden('.apn-details-view', true); 244 }); 245 246 $('select-apn').addEventListener('change', function(event) { 247 var data = $('connection-state').data; 248 var apnSelector = $('select-apn'); 249 if (apnSelector[apnSelector.selectedIndex].value != -1) { 250 var apnList = data.providerApnList.value; 251 chrome.send('setApn', [data.servicePath, 252 stringFromValue(apnList[apnSelector.selectedIndex].apn), 253 stringFromValue(apnList[apnSelector.selectedIndex].username), 254 stringFromValue(apnList[apnSelector.selectedIndex].password)] 255 ); 256 data.selectedApn = apnSelector.selectedIndex; 257 } else if (apnSelector.selectedIndex == data.userApnIndex) { 258 chrome.send('setApn', [data.servicePath, 259 stringFromValue(data.userApn.apn), 260 stringFromValue(data.userApn.username), 261 stringFromValue(data.userApn.password)]); 262 data.selectedApn = apnSelector.selectedIndex; 263 } else { 264 $('cellular-apn').value = stringFromValue(data.apn.apn); 265 $('cellular-apn-username').value = stringFromValue(data.apn.username); 266 $('cellular-apn-password').value = stringFromValue(data.apn.password); 267 268 updateHidden('.apn-list-view', true); 269 updateHidden('.apn-details-view', false); 270 } 271 }); 272 273 $('sim-card-lock-enabled').addEventListener('click', function(event) { 274 var newValue = $('sim-card-lock-enabled').checked; 275 // Leave value as is because user needs to enter PIN code first. 276 // When PIN will be entered and value changed, 277 // we'll update UI to reflect that change. 278 $('sim-card-lock-enabled').checked = !newValue; 279 chrome.send('setSimCardLock', [newValue]); 280 }); 281 $('change-pin').addEventListener('click', function(event) { 282 chrome.send('changePin'); 283 }); 284 285 // Proxy 286 ['proxy-host-single-port', 287 'secure-proxy-port', 288 'socks-port', 289 'ftp-proxy-port', 290 'proxy-host-port' 291 ].forEach(function(id) { 292 options.PrefPortNumber.decorate($(id)); 293 }); 294 295 options.proxyexceptions.ProxyExceptions.decorate($('ignored-host-list')); 296 $('remove-host').addEventListener('click', 297 this.handleRemoveProxyExceptions_); 298 $('add-host').addEventListener('click', this.handleAddProxyException_); 299 $('direct-proxy').addEventListener('click', this.disableManualProxy_); 300 $('manual-proxy').addEventListener('click', this.enableManualProxy_); 301 $('auto-proxy').addEventListener('click', this.disableManualProxy_); 302 $('proxy-all-protocols').addEventListener('click', 303 this.toggleSingleProxy_); 304 $('proxy-use-pac-url').addEventListener('change', 305 this.handleAutoConfigProxy_); 306 307 observePrefsUI($('direct-proxy')); 308 observePrefsUI($('manual-proxy')); 309 observePrefsUI($('auto-proxy')); 310 observePrefsUI($('proxy-all-protocols')); 311 observePrefsUI($('proxy-use-pac-url')); 312 313 $('ip-automatic-configuration-checkbox').addEventListener('click', 314 this.handleIpAutoConfig_); 315 $('automatic-dns-radio').addEventListener('click', 316 this.handleNameServerTypeChange_); 317 $('google-dns-radio').addEventListener('click', 318 this.handleNameServerTypeChange_); 319 $('user-dns-radio').addEventListener('click', 320 this.handleNameServerTypeChange_); 321 322 // We only load this string if we have the string data available 323 // because the proxy settings page on the login screen re-uses the 324 // proxy sub-page from the internet options, and it doesn't ever 325 // show the DNS settings, so we don't need this string there. 326 // The string isn't available because 327 // chrome://settings-frame/strings.js (where the string is 328 // stored) is not accessible from the login screen. 329 // TODO(pneubeck): Remove this once i18n of the proxy dialog on the login 330 // page is fixed. http://crbug.com/242865 331 if (loadTimeData.data_) { 332 $('google-dns-label').innerHTML = 333 loadTimeData.getString('googleNameServers'); 334 } 335 }, 336 337 /** 338 * Handler for "add" event fired from userNameEdit. 339 * @param {Event} e Add event fired from userNameEdit. 340 * @private 341 */ 342 handleAddProxyException_: function(e) { 343 var exception = $('new-host').value; 344 $('new-host').value = ''; 345 346 exception = exception.trim(); 347 if (exception) 348 $('ignored-host-list').addException(exception); 349 }, 350 351 /** 352 * Handler for when the remove button is clicked 353 * @param {Event} e The click event. 354 * @private 355 */ 356 handleRemoveProxyExceptions_: function(e) { 357 var selectedItems = $('ignored-host-list').selectedItems; 358 for (var x = 0; x < selectedItems.length; x++) { 359 $('ignored-host-list').removeException(selectedItems[x]); 360 } 361 }, 362 363 /** 364 * Handler for when the IP automatic configuration checkbox is clicked. 365 * @param {Event} e The click event. 366 * @private 367 */ 368 handleIpAutoConfig_: function(e) { 369 var checked = $('ip-automatic-configuration-checkbox').checked; 370 var fields = [$('ip-address'), $('ip-netmask'), $('ip-gateway')]; 371 for (var i = 0; i < fields.length; ++i) { 372 fields[i].editable = !checked; 373 if (checked) { 374 var model = fields[i].model; 375 model.value = model.automatic; 376 fields[i].model = model; 377 } 378 } 379 if (!checked) 380 $('ip-address').focus(); 381 }, 382 383 /** 384 * Handler for when the name server selection changes. 385 * @param {Event} e The click event. 386 * @private 387 */ 388 handleNameServerTypeChange_: function(event) { 389 var type = event.target.value; 390 DetailsInternetPage.updateNameServerDisplay(type); 391 }, 392 393 /** 394 * Update details page controls. 395 * @private 396 */ 397 updateControls: function() { 398 // Only show ipconfig section if network is connected OR if nothing on 399 // this device is connected. This is so that you can fix the ip configs 400 // if you can't connect to any network. 401 // TODO(chocobo): Once ipconfig is moved to flimflam service objects, 402 // we need to redo this logic to allow configuration of all networks. 403 $('ipconfig-section').hidden = !this.connected && this.deviceConnected; 404 $('ipconfig-dns-section').hidden = 405 !this.connected && this.deviceConnected; 406 407 // Network type related. 408 updateHidden('#details-internet-page .cellular-details', !this.cellular); 409 updateHidden('#details-internet-page .wifi-details', !this.wireless); 410 updateHidden('#details-internet-page .wimax-details', !this.wimax); 411 updateHidden('#details-internet-page .vpn-details', !this.vpn); 412 updateHidden('#details-internet-page .proxy-details', !this.showProxy); 413 // Conditionally call updateHidden on .gsm-only, so that we don't unhide 414 // a previously hidden element. 415 if (this.gsm) 416 updateHidden('#details-internet-page .cdma-only', true); 417 else 418 updateHidden('#details-internet-page .gsm-only', true); 419 /* Network information merged into the Wifi tab for wireless networks 420 unless the option is set for enabling a static IP configuration. */ 421 updateHidden('#details-internet-page .network-details', 422 (this.wireless && !this.showStaticIPConfig) || this.vpn); 423 updateHidden('#details-internet-page .wifi-network-setting', 424 this.showStaticIPConfig); 425 426 // Wifi - Password and shared. 427 updateHidden('#details-internet-page #password-details', 428 !this.wireless || !this.password); 429 updateHidden('#details-internet-page #wifi-shared-network', 430 !this.shared); 431 updateHidden('#details-internet-page #prefer-network', 432 !this.showPreferred); 433 434 // WiMAX. 435 updateHidden('#details-internet-page #wimax-shared-network', 436 !this.shared); 437 438 // Proxy 439 this.updateProxyBannerVisibility_(); 440 this.toggleSingleProxy_(); 441 if ($('manual-proxy').checked) 442 this.enableManualProxy_(); 443 else 444 this.disableManualProxy_(); 445 }, 446 447 /** 448 * Updates info banner visibility state. This function shows the banner 449 * if proxy is managed or shared-proxies is off for shared network. 450 * @private 451 */ 452 updateProxyBannerVisibility_: function() { 453 var bannerDiv = $('network-proxy-info-banner'); 454 if (!loadTimeData.data_) { 455 // TODO(pneubeck): This temporarily prevents an exception below until 456 // i18n of the proxy dialog on the login page is 457 // fixed. http://crbug.com/242865 458 bannerDiv.hidden = true; 459 return; 460 } 461 462 // Show banner and determine its message if necessary. 463 var controlledBy = $('direct-proxy').controlledBy; 464 if (!controlledBy || controlledBy == '') { 465 bannerDiv.hidden = true; 466 } else { 467 bannerDiv.hidden = false; 468 // The possible banner texts are loaded in proxy_handler.cc. 469 var bannerText = 'proxyBanner' + controlledBy.charAt(0).toUpperCase() + 470 controlledBy.slice(1); 471 $('banner-text').textContent = loadTimeData.getString(bannerText); 472 } 473 }, 474 475 /** 476 * Handler for when the user clicks on the checkbox to allow a 477 * single proxy usage. 478 * @private 479 * @param {Event} e Click Event. 480 */ 481 toggleSingleProxy_: function(e) { 482 if ($('proxy-all-protocols').checked) { 483 $('multi-proxy').hidden = true; 484 $('single-proxy').hidden = false; 485 } else { 486 $('multi-proxy').hidden = false; 487 $('single-proxy').hidden = true; 488 } 489 }, 490 491 /** 492 * Handler for when the user clicks on the checkbox to enter 493 * auto configuration URL. 494 * @private 495 * @param {Event} e Click Event. 496 */ 497 handleAutoConfigProxy_: function(e) { 498 $('proxy-pac-url').disabled = !$('proxy-use-pac-url').checked; 499 }, 500 501 /** 502 * Handler for selecting a radio button that will disable the manual 503 * controls. 504 * @private 505 * @param {Event} e Click event. 506 */ 507 disableManualProxy_: function(e) { 508 $('ignored-host-list').disabled = true; 509 $('new-host').disabled = true; 510 $('remove-host').disabled = true; 511 $('add-host').disabled = true; 512 $('proxy-all-protocols').disabled = true; 513 $('proxy-host-name').disabled = true; 514 $('proxy-host-port').disabled = true; 515 $('proxy-host-single-name').disabled = true; 516 $('proxy-host-single-port').disabled = true; 517 $('secure-proxy-host-name').disabled = true; 518 $('secure-proxy-port').disabled = true; 519 $('ftp-proxy').disabled = true; 520 $('ftp-proxy-port').disabled = true; 521 $('socks-host').disabled = true; 522 $('socks-port').disabled = true; 523 $('proxy-use-pac-url').disabled = $('auto-proxy').disabled || 524 !$('auto-proxy').checked; 525 $('proxy-pac-url').disabled = $('proxy-use-pac-url').disabled || 526 !$('proxy-use-pac-url').checked; 527 $('auto-proxy-parms').hidden = !$('auto-proxy').checked; 528 $('manual-proxy-parms').hidden = !$('manual-proxy').checked; 529 chrome.send('coreOptionsUserMetricsAction', 530 ['Options_NetworkManualProxy_Disable']); 531 }, 532 533 /** 534 * Handler for selecting a radio button that will enable the manual 535 * controls. 536 * @private 537 * @param {Event} e Click event. 538 */ 539 enableManualProxy_: function(e) { 540 $('ignored-host-list').redraw(); 541 var allDisabled = $('manual-proxy').disabled; 542 $('ignored-host-list').disabled = allDisabled; 543 $('new-host').disabled = allDisabled; 544 $('remove-host').disabled = allDisabled; 545 $('add-host').disabled = allDisabled; 546 $('proxy-all-protocols').disabled = allDisabled; 547 $('proxy-host-name').disabled = allDisabled; 548 $('proxy-host-port').disabled = allDisabled; 549 $('proxy-host-single-name').disabled = allDisabled; 550 $('proxy-host-single-port').disabled = allDisabled; 551 $('secure-proxy-host-name').disabled = allDisabled; 552 $('secure-proxy-port').disabled = allDisabled; 553 $('ftp-proxy').disabled = allDisabled; 554 $('ftp-proxy-port').disabled = allDisabled; 555 $('socks-host').disabled = allDisabled; 556 $('socks-port').disabled = allDisabled; 557 $('proxy-use-pac-url').disabled = true; 558 $('proxy-pac-url').disabled = true; 559 $('auto-proxy-parms').hidden = !$('auto-proxy').checked; 560 $('manual-proxy-parms').hidden = !$('manual-proxy').checked; 561 chrome.send('coreOptionsUserMetricsAction', 562 ['Options_NetworkManualProxy_Enable']); 563 }, 564 }; 565 566 /** 567 * Enables or Disables all buttons that provide operations on the cellular 568 * network. 569 */ 570 DetailsInternetPage.changeCellularButtonsState = function(disable) { 571 var buttonsToDisableList = 572 new Array('details-internet-login', 573 'details-internet-disconnect', 574 'details-internet-configure', 575 'activate-details', 576 'buyplan-details', 577 'view-account-details'); 578 579 for (var i = 0; i < buttonsToDisableList.length; ++i) { 580 button = $(buttonsToDisableList[i]); 581 button.disabled = disable; 582 } 583 }; 584 585 /** 586 * Shows a spinner while the carrier is changed. 587 */ 588 DetailsInternetPage.showCarrierChangeSpinner = function(visible) { 589 $('switch-carrier-spinner').hidden = !visible; 590 // Disable any buttons that allow us to operate on cellular networks. 591 DetailsInternetPage.changeCellularButtonsState(visible); 592 }; 593 594 /** 595 * Changes the network carrier. 596 */ 597 DetailsInternetPage.handleCarrierChanged = function() { 598 var carrierSelector = $('select-carrier'); 599 var carrier = carrierSelector[carrierSelector.selectedIndex].textContent; 600 DetailsInternetPage.showCarrierChangeSpinner(true); 601 var data = $('connection-state').data; 602 chrome.send('setCarrier', [data.servicePath, carrier]); 603 }; 604 605 /** 606 * Performs minimal initialization of the InternetDetails dialog in 607 * preparation for showing proxy-setttings. 608 */ 609 DetailsInternetPage.initializeProxySettings = function() { 610 var detailsPage = DetailsInternetPage.getInstance(); 611 detailsPage.initializePageContents_(); 612 }; 613 614 /** 615 * Displays the InternetDetails dialog with only the proxy settings visible. 616 */ 617 DetailsInternetPage.showProxySettings = function() { 618 var detailsPage = DetailsInternetPage.getInstance(); 619 $('network-details-header').hidden = true; 620 $('buyplan-details').hidden = true; 621 $('activate-details').hidden = true; 622 $('view-account-details').hidden = true; 623 $('web-proxy-auto-discovery').hidden = true; 624 detailsPage.cellular = false; 625 detailsPage.wireless = false; 626 detailsPage.vpn = false; 627 detailsPage.showProxy = true; 628 updateHidden('#internet-tab', true); 629 updateHidden('#details-tab-strip', true); 630 updateHidden('#details-internet-page .action-area', true); 631 detailsPage.updateControls(); 632 detailsPage.visible = true; 633 chrome.send('coreOptionsUserMetricsAction', 634 ['Options_NetworkShowProxyTab']); 635 }; 636 637 /** 638 * Initializes even handling for keyboard driven flow. 639 */ 640 DetailsInternetPage.initializeKeyboardFlow = function() { 641 keyboard.initializeKeyboardFlow(); 642 }; 643 644 DetailsInternetPage.updateProxySettings = function(type) { 645 var proxyHost = null, 646 proxyPort = null; 647 648 if (type == 'cros.session.proxy.singlehttp') { 649 proxyHost = 'proxy-host-single-name'; 650 proxyPort = 'proxy-host-single-port'; 651 }else if (type == 'cros.session.proxy.httpurl') { 652 proxyHost = 'proxy-host-name'; 653 proxyPort = 'proxy-host-port'; 654 }else if (type == 'cros.session.proxy.httpsurl') { 655 proxyHost = 'secure-proxy-host-name'; 656 proxyPort = 'secure-proxy-port'; 657 }else if (type == 'cros.session.proxy.ftpurl') { 658 proxyHost = 'ftp-proxy'; 659 proxyPort = 'ftp-proxy-port'; 660 }else if (type == 'cros.session.proxy.socks') { 661 proxyHost = 'socks-host'; 662 proxyPort = 'socks-port'; 663 }else { 664 return; 665 } 666 667 var hostValue = $(proxyHost).value; 668 if (hostValue.indexOf(':') !== -1) { 669 if (hostValue.match(/:/g).length == 1) { 670 hostValue = hostValue.split(':'); 671 $(proxyHost).value = hostValue[0]; 672 $(proxyPort).value = hostValue[1]; 673 } 674 } 675 }; 676 677 DetailsInternetPage.updateCarrier = function() { 678 DetailsInternetPage.showCarrierChangeSpinner(false); 679 }; 680 681 DetailsInternetPage.updateSecurityTab = function(requirePin) { 682 $('sim-card-lock-enabled').checked = requirePin; 683 $('change-pin').hidden = !requirePin; 684 }; 685 686 DetailsInternetPage.loginFromDetails = function() { 687 var data = $('connection-state').data; 688 var servicePath = data.servicePath; 689 chrome.send('networkCommand', [String(data.type), 690 servicePath, 691 'connect']); 692 OptionsPage.closeOverlay(); 693 }; 694 695 DetailsInternetPage.disconnectNetwork = function() { 696 var data = $('connection-state').data; 697 var servicePath = data.servicePath; 698 chrome.send('networkCommand', [String(data.type), 699 servicePath, 700 'disconnect']); 701 OptionsPage.closeOverlay(); 702 }; 703 704 DetailsInternetPage.configureNetwork = function() { 705 var data = $('connection-state').data; 706 var servicePath = data.servicePath; 707 chrome.send('networkCommand', [String(data.type), 708 servicePath, 709 'configure']); 710 OptionsPage.closeOverlay(); 711 }; 712 713 DetailsInternetPage.activateFromDetails = function() { 714 var data = $('connection-state').data; 715 var servicePath = data.servicePath; 716 if (data.type == Constants.TYPE_CELLULAR) { 717 chrome.send('networkCommand', [String(data.type), 718 servicePath, 719 'activate']); 720 } 721 OptionsPage.closeOverlay(); 722 }; 723 724 DetailsInternetPage.setDetails = function() { 725 var data = $('connection-state').data; 726 var servicePath = data.servicePath; 727 if (data.type == Constants.TYPE_WIFI) { 728 sendCheckedIfEnabled(servicePath, 'setPreferNetwork', 729 $('prefer-network-wifi')); 730 sendCheckedIfEnabled(servicePath, 'setAutoConnect', 731 $('auto-connect-network-wifi')); 732 } else if (data.type == Constants.TYPE_WIMAX) { 733 sendCheckedIfEnabled(servicePath, 'setAutoConnect', 734 $('auto-connect-network-wimax')); 735 } else if (data.type == Constants.TYPE_CELLULAR) { 736 sendCheckedIfEnabled(servicePath, 'setAutoConnect', 737 $('auto-connect-network-cellular')); 738 } else if (data.type == Constants.TYPE_VPN) { 739 chrome.send('setServerHostname', 740 [servicePath, 741 $('inet-server-hostname').value]); 742 sendCheckedIfEnabled(servicePath, 'setAutoConnect', 743 $('auto-connect-network-vpn')); 744 } 745 746 var nameServerTypes = ['automatic', 'google', 'user']; 747 var nameServerType = 'automatic'; 748 for (var i = 0; i < nameServerTypes.length; ++i) { 749 if ($(nameServerTypes[i] + '-dns-radio').checked) { 750 nameServerType = nameServerTypes[i]; 751 break; 752 } 753 } 754 755 // Skip any empty values. 756 var userNameServers = []; 757 for (var i = 1; i <= 4; ++i) { 758 var nameServerField = $('ipconfig-dns' + i); 759 if (nameServerField && nameServerField.model && 760 nameServerField.model.value) { 761 userNameServers.push(nameServerField.model.value); 762 } 763 } 764 765 userNameServers = userNameServers.join(','); 766 767 chrome.send('setIPConfig', 768 [servicePath, 769 Boolean($('ip-automatic-configuration-checkbox').checked), 770 $('ip-address').model.value || '', 771 $('ip-netmask').model.value || '', 772 $('ip-gateway').model.value || '', 773 nameServerType, 774 userNameServers]); 775 OptionsPage.closeOverlay(); 776 }; 777 778 DetailsInternetPage.updateNameServerDisplay = function(type) { 779 var editable = type == 'user'; 780 var fields = [$('ipconfig-dns1'), $('ipconfig-dns2'), 781 $('ipconfig-dns3'), $('ipconfig-dns4')]; 782 for (var i = 0; i < fields.length; ++i) { 783 fields[i].editable = editable; 784 } 785 if (editable) 786 $('ipconfig-dns1').focus(); 787 788 var automaticDns = $('automatic-dns-display'); 789 var googleDns = $('google-dns-display'); 790 var userDns = $('user-dns-settings'); 791 switch (type) { 792 case 'automatic': 793 automaticDns.setAttribute('selected', ''); 794 googleDns.removeAttribute('selected'); 795 userDns.removeAttribute('selected'); 796 break; 797 case 'google': 798 automaticDns.removeAttribute('selected'); 799 googleDns.setAttribute('selected', ''); 800 userDns.removeAttribute('selected'); 801 break; 802 case 'user': 803 automaticDns.removeAttribute('selected'); 804 googleDns.removeAttribute('selected'); 805 userDns.setAttribute('selected', ''); 806 break; 807 } 808 }; 809 810 DetailsInternetPage.updateConnectionButtonVisibilty = function(data) { 811 $('details-internet-login').hidden = data.connected; 812 $('details-internet-login').disabled = data.disableConnectButton; 813 814 if (!data.connected && 815 ((data.type == Constants.TYPE_WIFI && data.encryption) || 816 data.type == Constants.TYPE_WIMAX || 817 data.type == Constants.TYPE_VPN)) { 818 $('details-internet-configure').hidden = false; 819 } else if (data.type == Constants.TYPE_ETHERNET) { 820 // Ethernet (802.1x) can be configured while connected. 821 $('details-internet-configure').hidden = false; 822 } else { 823 $('details-internet-configure').hidden = true; 824 } 825 826 if (data.type == Constants.TYPE_ETHERNET) 827 $('details-internet-disconnect').hidden = true; 828 else 829 $('details-internet-disconnect').hidden = !data.connected; 830 }; 831 832 DetailsInternetPage.updateConnectionData = function(update) { 833 var detailsPage = DetailsInternetPage.getInstance(); 834 if (!detailsPage.visible) 835 return; 836 837 var data = $('connection-state').data; 838 if (!data) 839 return; 840 841 if (update.servicePath != data.servicePath) 842 return; 843 844 // Update our cached data object. 845 updateDataObject(data, update); 846 847 detailsPage.deviceConnected = data.deviceConnected; 848 detailsPage.connecting = data.connecting; 849 detailsPage.connected = data.connected; 850 $('connection-state').textContent = data.connectionState; 851 852 this.updateConnectionButtonVisibilty(data); 853 854 if (data.type == Constants.TYPE_WIFI) { 855 $('wifi-connection-state').textContent = data.connectionState; 856 } else if (data.type == Constants.TYPE_WIMAX) { 857 $('wimax-connection-state').textContent = data.connectionState; 858 } else if (data.type == Constants.TYPE_CELLULAR) { 859 $('activation-state').textContent = data.activationState; 860 861 $('buyplan-details').hidden = !data.showBuyButton; 862 $('view-account-details').hidden = !data.showViewAccountButton; 863 864 $('activate-details').hidden = !data.showActivateButton; 865 if (data.showActivateButton) 866 $('details-internet-login').hidden = true; 867 } 868 869 $('connection-state').data = data; 870 }; 871 872 DetailsInternetPage.showDetailedInfo = function(data) { 873 var detailsPage = DetailsInternetPage.getInstance(); 874 875 // Populate header 876 $('network-details-title').textContent = data.networkName; 877 var statusKey = data.connected ? 'networkConnected' : 878 'networkNotConnected'; 879 $('network-details-subtitle-status').textContent = 880 loadTimeData.getString(statusKey); 881 var typeKey = null; 882 switch (data.type) { 883 case Constants.TYPE_ETHERNET: 884 typeKey = 'ethernetTitle'; 885 break; 886 case Constants.TYPE_WIFI: 887 typeKey = 'wifiTitle'; 888 break; 889 case Constants.TYPE_WIMAX: 890 typeKey = 'wimaxTitle'; 891 break; 892 case Constants.TYPE_CELLULAR: 893 typeKey = 'cellularTitle'; 894 break; 895 case Constants.TYPE_VPN: 896 typeKey = 'vpnTitle'; 897 break; 898 } 899 var typeLabel = $('network-details-subtitle-type'); 900 var typeSeparator = $('network-details-subtitle-separator'); 901 if (typeKey) { 902 typeLabel.textContent = loadTimeData.getString(typeKey); 903 typeLabel.hidden = false; 904 typeSeparator.hidden = false; 905 } else { 906 typeLabel.hidden = true; 907 typeSeparator.hidden = true; 908 } 909 910 // TODO(chocobo): Is this hack to cache the data here reasonable? 911 // TODO(kevers): Find more appropriate place to cache data. 912 $('connection-state').data = data; 913 914 $('buyplan-details').hidden = true; 915 $('activate-details').hidden = true; 916 $('view-account-details').hidden = true; 917 918 this.updateConnectionButtonVisibilty(data); 919 920 $('web-proxy-auto-discovery').hidden = true; 921 922 detailsPage.deviceConnected = data.deviceConnected; 923 detailsPage.connecting = data.connecting; 924 detailsPage.connected = data.connected; 925 detailsPage.showProxy = data.showProxy; 926 if (detailsPage.showProxy) 927 chrome.send('selectNetwork', [data.servicePath]); 928 929 detailsPage.showStaticIPConfig = data.showStaticIPConfig; 930 $('connection-state').textContent = data.connectionState; 931 932 var ipAutoConfig = data.ipAutoConfig ? 'automatic' : 'user'; 933 $('ip-automatic-configuration-checkbox').checked = data.ipAutoConfig; 934 var inetAddress = {autoConfig: ipAutoConfig}; 935 var inetNetmask = {autoConfig: ipAutoConfig}; 936 var inetGateway = {autoConfig: ipAutoConfig}; 937 938 if (data.ipconfig.value) { 939 inetAddress.automatic = data.ipconfig.value.address; 940 inetAddress.value = data.ipconfig.value.address; 941 inetNetmask.automatic = data.ipconfig.value.netmask; 942 inetNetmask.value = data.ipconfig.value.netmask; 943 inetGateway.automatic = data.ipconfig.value.gateway; 944 inetGateway.value = data.ipconfig.value.gateway; 945 if (data.ipconfig.value.webProxyAutoDiscoveryUrl) { 946 $('web-proxy-auto-discovery').hidden = false; 947 $('web-proxy-auto-discovery-url').value = 948 data.ipconfig.value.webProxyAutoDiscoveryUrl; 949 } 950 } 951 952 // Override the "automatic" values with the real saved DHCP values, 953 // if they are set. 954 if (data.savedIP.address) { 955 inetAddress.automatic = data.savedIP.address; 956 inetAddress.value = data.savedIP.address; 957 } 958 if (data.savedIP.netmask) { 959 inetNetmask.automatic = data.savedIP.netmask; 960 inetNetmask.value = data.savedIP.netmask; 961 } 962 if (data.savedIP.gateway) { 963 inetGateway.automatic = data.savedIP.gateway; 964 inetGateway.value = data.savedIP.gateway; 965 } 966 967 if (ipAutoConfig == 'user') { 968 if (data.staticIP.value.address) { 969 inetAddress.value = data.staticIP.value.address; 970 inetAddress.user = data.staticIP.value.address; 971 } 972 if (data.staticIP.value.netmask) { 973 inetNetmask.value = data.staticIP.value.netmask; 974 inetNetmask.user = data.staticIP.value.netmask; 975 } 976 if (data.staticIP.value.gateway) { 977 inetGateway.value = data.staticIP.value.gateway; 978 inetGateway.user = data.staticIP.value.gateway; 979 } 980 } 981 982 var configureAddressField = function(field, model) { 983 IPAddressField.decorate(field); 984 field.model = model; 985 field.editable = model.autoConfig == 'user'; 986 }; 987 988 configureAddressField($('ip-address'), inetAddress); 989 configureAddressField($('ip-netmask'), inetNetmask); 990 configureAddressField($('ip-gateway'), inetGateway); 991 992 var inetNameServers = ''; 993 if (data.ipconfig.value && data.ipconfig.value.nameServers) { 994 inetNameServers = data.ipconfig.value.nameServers; 995 $('automatic-dns-display').textContent = inetNameServers; 996 } 997 998 if (data.savedIP && data.savedIP.nameServers) 999 $('automatic-dns-display').textContent = data.savedIP.nameServers; 1000 1001 if (data.nameServersGoogle) 1002 $('google-dns-display').textContent = data.nameServersGoogle; 1003 1004 var nameServersUser = []; 1005 if (data.staticIP.value.nameServers) 1006 nameServersUser = data.staticIP.value.nameServers.split(','); 1007 1008 var nameServerModels = []; 1009 for (var i = 0; i < 4; ++i) 1010 nameServerModels.push({value: nameServersUser[i] || ''}); 1011 1012 $(data.nameServerType + '-dns-radio').checked = true; 1013 configureAddressField($('ipconfig-dns1'), nameServerModels[0]); 1014 configureAddressField($('ipconfig-dns2'), nameServerModels[1]); 1015 configureAddressField($('ipconfig-dns3'), nameServerModels[2]); 1016 configureAddressField($('ipconfig-dns4'), nameServerModels[3]); 1017 1018 DetailsInternetPage.updateNameServerDisplay(data.nameServerType); 1019 1020 if (data.hardwareAddress) { 1021 $('hardware-address').textContent = data.hardwareAddress; 1022 $('hardware-address-row').style.display = 'table-row'; 1023 } else { 1024 // This is most likely a device without a hardware address. 1025 $('hardware-address-row').style.display = 'none'; 1026 } 1027 if (data.type == Constants.TYPE_WIFI) { 1028 OptionsPage.showTab($('wifi-network-nav-tab')); 1029 detailsPage.wireless = true; 1030 detailsPage.vpn = false; 1031 detailsPage.ethernet = false; 1032 detailsPage.cellular = false; 1033 detailsPage.gsm = false; 1034 detailsPage.wimax = false; 1035 detailsPage.shared = data.shared; 1036 $('wifi-connection-state').textContent = data.connectionState; 1037 $('wifi-ssid').textContent = data.ssid; 1038 if (data.bssid && data.bssid.length > 0) { 1039 $('wifi-bssid').textContent = data.bssid; 1040 $('wifi-bssid-entry').hidden = false; 1041 } else { 1042 $('wifi-bssid-entry').hidden = true; 1043 } 1044 $('wifi-ip-address').textContent = inetAddress.value; 1045 $('wifi-netmask').textContent = inetNetmask.value; 1046 $('wifi-gateway').textContent = inetGateway.value; 1047 $('wifi-name-servers').textContent = inetNameServers; 1048 if (data.encryption && data.encryption.length > 0) { 1049 $('wifi-security').textContent = data.encryption; 1050 $('wifi-security-entry').hidden = false; 1051 } else { 1052 $('wifi-security-entry').hidden = true; 1053 } 1054 // Frequency is in MHz. 1055 var frequency = loadTimeData.getString('inetFrequencyFormat'); 1056 frequency = frequency.replace('$1', data.frequency); 1057 $('wifi-frequency').textContent = frequency; 1058 // Signal strength as percentage. 1059 var signalStrength = loadTimeData.getString('inetSignalStrengthFormat'); 1060 signalStrength = signalStrength.replace('$1', data.strength); 1061 $('wifi-signal-strength').textContent = signalStrength; 1062 if (data.hardwareAddress) { 1063 $('wifi-hardware-address').textContent = data.hardwareAddress; 1064 $('wifi-hardware-address-entry').hidden = false; 1065 } else { 1066 $('wifi-hardware-address-entry').hidden = true; 1067 } 1068 detailsPage.showPreferred = data.showPreferred; 1069 $('prefer-network-wifi').checked = data.preferred.value; 1070 $('prefer-network-wifi').disabled = !data.remembered; 1071 $('auto-connect-network-wifi').checked = data.autoConnect.value; 1072 $('auto-connect-network-wifi').disabled = !data.remembered; 1073 detailsPage.password = data.encrypted; 1074 } else if (data.type == Constants.TYPE_WIMAX) { 1075 OptionsPage.showTab($('wimax-network-nav-tab')); 1076 detailsPage.wimax = true; 1077 detailsPage.wireless = false; 1078 detailsPage.vpn = false; 1079 detailsPage.ethernet = false; 1080 detailsPage.cellular = false; 1081 detailsPage.gsm = false; 1082 detailsPage.shared = data.shared; 1083 detailsPage.showPreferred = data.showPreferred; 1084 $('wimax-connection-state').textContent = data.connectionState; 1085 $('auto-connect-network-wimax').checked = data.autoConnect.value; 1086 $('auto-connect-network-wimax').disabled = !data.remembered; 1087 if (data.identity) { 1088 $('wimax-eap-identity').textContent = data.identity; 1089 $('wimax-eap-identity-entry').hidden = false; 1090 } else { 1091 $('wimax-eap-identity-entry').hidden = true; 1092 } 1093 // Signal strength as percentage. 1094 var signalStrength = loadTimeData.getString('inetSignalStrengthFormat'); 1095 signalStrength = signalStrength.replace('$1', data.strength); 1096 $('wimax-signal-strength').textContent = signalStrength; 1097 } else if (data.type == Constants.TYPE_CELLULAR) { 1098 OptionsPage.showTab($('cellular-conn-nav-tab')); 1099 detailsPage.ethernet = false; 1100 detailsPage.wireless = false; 1101 detailsPage.wimax = false; 1102 detailsPage.vpn = false; 1103 detailsPage.cellular = true; 1104 if (data.showCarrierSelect && data.currentCarrierIndex != -1) { 1105 var carrierSelector = $('select-carrier'); 1106 carrierSelector.onchange = DetailsInternetPage.handleCarrierChanged; 1107 carrierSelector.options.length = 0; 1108 for (var i = 0; i < data.carriers.length; ++i) { 1109 var option = document.createElement('option'); 1110 option.textContent = data.carriers[i]; 1111 carrierSelector.add(option); 1112 } 1113 carrierSelector.selectedIndex = data.currentCarrierIndex; 1114 } else { 1115 $('service-name').textContent = data.serviceName; 1116 } 1117 1118 $('network-technology').textContent = data.networkTechnology; 1119 $('activation-state').textContent = data.activationState; 1120 $('roaming-state').textContent = data.roamingState; 1121 $('restricted-pool').textContent = data.restrictedPool; 1122 $('error-state').textContent = data.errorState; 1123 $('manufacturer').textContent = data.cellularManufacturer; 1124 $('model-id').textContent = data.modelId; 1125 $('firmware-revision').textContent = data.firmwareRevision; 1126 $('hardware-revision').textContent = data.hardwareRevision; 1127 $('mdn').textContent = data.mdn; 1128 $('operator-name').textContent = data.operatorName; 1129 $('operator-code').textContent = data.operatorCode; 1130 1131 // Make sure that GSM/CDMA specific properties that shouldn't be hidden 1132 // are visible. 1133 updateHidden('#details-internet-page .gsm-only', false); 1134 updateHidden('#details-internet-page .cdma-only', false); 1135 1136 // Show IMEI/ESN/MEID/MIN/PRL only if they are available. 1137 (function() { 1138 var setContentOrHide = function(property) { 1139 var value = data[property]; 1140 if (value) 1141 $(property).textContent = value; 1142 else 1143 $(property).parentElement.hidden = true; 1144 }; 1145 setContentOrHide('esn'); 1146 setContentOrHide('imei'); 1147 setContentOrHide('meid'); 1148 setContentOrHide('min'); 1149 setContentOrHide('prl-version'); 1150 })(); 1151 detailsPage.gsm = data.gsm; 1152 if (data.gsm) { 1153 $('iccid').textContent = stringFromValue(data.iccid); 1154 $('imsi').textContent = stringFromValue(data.imsi); 1155 1156 var apnSelector = $('select-apn'); 1157 // Clear APN lists, keep only last element that "other". 1158 while (apnSelector.length != 1) 1159 apnSelector.remove(0); 1160 var otherOption = apnSelector[0]; 1161 data.selectedApn = -1; 1162 data.userApnIndex = -1; 1163 var apnList = data.providerApnList.value; 1164 for (var i = 0; i < apnList.length; i++) { 1165 var option = document.createElement('option'); 1166 var localizedName = apnList[i].localizedName; 1167 var name = localizedName ? localizedName : apnList[i].name; 1168 var apn = apnList[i].apn; 1169 option.textContent = name ? (name + ' (' + apn + ')') : apn; 1170 option.value = i; 1171 // data.apn and data.lastGoodApn will always be defined, however 1172 // data.apn.apn and data.lastGoodApn.apn may not be. This is not a 1173 // problem, as apnList[i].apn will always be defined and the 1174 // comparisons below will work as expected. 1175 if ((data.apn.apn == apn && 1176 data.apn.username == apnList[i].username && 1177 data.apn.password == apnList[i].password) || 1178 (!data.apn.apn && 1179 data.lastGoodApn.apn == apn && 1180 data.lastGoodApn.username == apnList[i].username && 1181 data.lastGoodApn.password == apnList[i].password)) { 1182 data.selectedApn = i; 1183 } 1184 // Insert new option before "other" option. 1185 apnSelector.add(option, otherOption); 1186 } 1187 if (data.selectedApn == -1 && data.apn.apn) { 1188 var option = document.createElement('option'); 1189 option.textContent = data.apn.apn; 1190 option.value = -1; 1191 apnSelector.add(option, otherOption); 1192 data.selectedApn = apnSelector.length - 2; 1193 data.userApnIndex = data.selectedApn; 1194 } 1195 apnSelector.selectedIndex = data.selectedApn; 1196 updateHidden('.apn-list-view', false); 1197 updateHidden('.apn-details-view', true); 1198 DetailsInternetPage.updateSecurityTab(data.simCardLockEnabled.value); 1199 } 1200 $('auto-connect-network-cellular').checked = data.autoConnect.value; 1201 $('auto-connect-network-cellular').disabled = false; 1202 1203 $('buyplan-details').hidden = !data.showBuyButton; 1204 $('view-account-details').hidden = !data.showViewAccountButton; 1205 $('activate-details').hidden = !data.showActivateButton; 1206 if (data.showActivateButton) { 1207 $('details-internet-login').hidden = true; 1208 } 1209 } else if (data.type == Constants.TYPE_VPN) { 1210 OptionsPage.showTab($('vpn-nav-tab')); 1211 detailsPage.wireless = false; 1212 detailsPage.wimax = false; 1213 detailsPage.vpn = true; 1214 detailsPage.ethernet = false; 1215 detailsPage.cellular = false; 1216 detailsPage.gsm = false; 1217 $('inet-service-name').textContent = data.serviceName; 1218 $('inet-provider-type').textContent = data.providerType; 1219 $('inet-username').textContent = data.username; 1220 var inetServerHostname = $('inet-server-hostname'); 1221 inetServerHostname.value = data.serverHostname.value; 1222 inetServerHostname.resetHandler = function() { 1223 OptionsPage.hideBubble(); 1224 inetServerHostname.value = data.serverHostname.recommendedValue; 1225 }; 1226 $('auto-connect-network-vpn').checked = data.autoConnect.value; 1227 $('auto-connect-network-vpn').disabled = false; 1228 } else { 1229 OptionsPage.showTab($('internet-nav-tab')); 1230 detailsPage.ethernet = true; 1231 detailsPage.wireless = false; 1232 detailsPage.wimax = false; 1233 detailsPage.vpn = false; 1234 detailsPage.cellular = false; 1235 detailsPage.gsm = false; 1236 } 1237 1238 // Update controlled option indicators. 1239 indicators = cr.doc.querySelectorAll( 1240 '#details-internet-page .controlled-setting-indicator'); 1241 for (var i = 0; i < indicators.length; i++) { 1242 var propName = indicators[i].getAttribute('data'); 1243 if (!propName || !data[propName]) 1244 continue; 1245 var propData = data[propName]; 1246 // Create a synthetic pref change event decorated as 1247 // CoreOptionsHandler::CreateValueForPref() does. 1248 var event = new Event(name); 1249 event.value = { 1250 value: propData.value, 1251 controlledBy: propData.controlledBy, 1252 recommendedValue: propData.recommendedValue, 1253 }; 1254 indicators[i].handlePrefChange(event); 1255 var forElement = $(indicators[i].getAttribute('for')); 1256 if (forElement) { 1257 if (propData.controlledBy == 'policy') 1258 forElement.disabled = true; 1259 if (forElement.resetHandler) 1260 indicators[i].resetHandler = forElement.resetHandler; 1261 } 1262 } 1263 1264 detailsPage.updateControls(); 1265 1266 // Don't show page name in address bar and in history to prevent people 1267 // navigate here by hand and solve issue with page session restore. 1268 OptionsPage.showPageByName('detailsInternetPage', false); 1269 }; 1270 1271 return { 1272 DetailsInternetPage: DetailsInternetPage 1273 }; 1274 }); 1275