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', function() { 6 var OptionsPage = options.OptionsPage; 7 var ArrayDataModel = cr.ui.ArrayDataModel; 8 var RepeatingButton = cr.ui.RepeatingButton; 9 10 // 11 // BrowserOptions class 12 // Encapsulated handling of browser options page. 13 // 14 function BrowserOptions() { 15 OptionsPage.call(this, 'settings', loadTimeData.getString('settingsTitle'), 16 'settings'); 17 } 18 19 cr.addSingletonGetter(BrowserOptions); 20 21 BrowserOptions.prototype = { 22 __proto__: options.OptionsPage.prototype, 23 24 /** 25 * Keeps track of whether the user is signed in or not. 26 * @type {boolean} 27 * @private 28 */ 29 signedIn_: false, 30 31 /** 32 * Keeps track of whether |onShowHomeButtonChanged_| has been called. See 33 * |onShowHomeButtonChanged_|. 34 * @type {boolean} 35 * @private 36 */ 37 onShowHomeButtonChangedCalled_: false, 38 39 /** 40 * Track if page initialization is complete. All C++ UI handlers have the 41 * chance to manipulate page content within their InitializePage methods. 42 * This flag is set to true after all initializers have been called. 43 * @type {boolean} 44 * @private 45 */ 46 initializationComplete_: false, 47 48 /** @override */ 49 initializePage: function() { 50 OptionsPage.prototype.initializePage.call(this); 51 var self = this; 52 53 // Ensure that navigation events are unblocked on uber page. A reload of 54 // the settings page while an overlay is open would otherwise leave uber 55 // page in a blocked state, where tab switching is not possible. 56 uber.invokeMethodOnParent('stopInterceptingEvents'); 57 58 window.addEventListener('message', this.handleWindowMessage_.bind(this)); 59 60 $('advanced-settings-expander').onclick = function() { 61 self.toggleSectionWithAnimation_( 62 $('advanced-settings'), 63 $('advanced-settings-container')); 64 65 // If the link was focused (i.e., it was activated using the keyboard) 66 // and it was used to show the section (rather than hiding it), focus 67 // the first element in the container. 68 if (document.activeElement === $('advanced-settings-expander') && 69 $('advanced-settings').style.height === '') { 70 var focusElement = $('advanced-settings-container').querySelector( 71 'button, input, list, select, a[href]'); 72 if (focusElement) 73 focusElement.focus(); 74 } 75 } 76 77 $('advanced-settings').addEventListener('webkitTransitionEnd', 78 this.updateAdvancedSettingsExpander_.bind(this)); 79 80 if (cr.isChromeOS) 81 UIAccountTweaks.applyGuestModeVisibility(document); 82 83 // Sync (Sign in) section. 84 this.updateSyncState_(loadTimeData.getValue('syncData')); 85 86 $('start-stop-sync').onclick = function(event) { 87 if (self.signedIn_) 88 SyncSetupOverlay.showStopSyncingUI(); 89 else if (cr.isChromeOS) 90 SyncSetupOverlay.showSetupUI(); 91 else 92 SyncSetupOverlay.startSignIn(); 93 }; 94 $('customize-sync').onclick = function(event) { 95 SyncSetupOverlay.showSetupUI(); 96 }; 97 98 // Internet connection section (ChromeOS only). 99 if (cr.isChromeOS) { 100 options.network.NetworkList.decorate($('network-list')); 101 options.network.NetworkList.refreshNetworkData( 102 loadTimeData.getValue('networkData')); 103 } 104 105 // On Startup section. 106 Preferences.getInstance().addEventListener('session.restore_on_startup', 107 this.onRestoreOnStartupChanged_.bind(this)); 108 Preferences.getInstance().addEventListener( 109 'session.urls_to_restore_on_startup', 110 function(event) { 111 $('startup-set-pages').disabled = event.value.disabled; 112 }); 113 114 $('startup-set-pages').onclick = function() { 115 OptionsPage.navigateToPage('startup'); 116 }; 117 118 // Appearance section. 119 Preferences.getInstance().addEventListener('browser.show_home_button', 120 this.onShowHomeButtonChanged_.bind(this)); 121 122 Preferences.getInstance().addEventListener('homepage', 123 this.onHomePageChanged_.bind(this)); 124 Preferences.getInstance().addEventListener('homepage_is_newtabpage', 125 this.onHomePageIsNtpChanged_.bind(this)); 126 127 $('change-home-page').onclick = function(event) { 128 OptionsPage.navigateToPage('homePageOverlay'); 129 }; 130 131 if ($('set-wallpaper')) { 132 $('set-wallpaper').onclick = function(event) { 133 chrome.send('openWallpaperManager'); 134 }; 135 } 136 137 $('themes-gallery').onclick = function(event) { 138 window.open(loadTimeData.getString('themesGalleryURL')); 139 }; 140 $('themes-reset').onclick = function(event) { 141 chrome.send('themesReset'); 142 }; 143 144 if (loadTimeData.getBoolean('profileIsManaged')) { 145 if ($('themes-native-button')) { 146 $('themes-native-button').disabled = true; 147 $('themes-native-button').hidden = true; 148 } 149 // Supervised users have just one default theme, even on Linux. So use 150 // the same button for Linux as for the other platforms. 151 $('themes-reset').textContent = loadTimeData.getString('themesReset'); 152 } 153 154 // Device section (ChromeOS only). 155 if (cr.isChromeOS) { 156 $('keyboard-settings-button').onclick = function(evt) { 157 OptionsPage.navigateToPage('keyboard-overlay'); 158 }; 159 $('pointer-settings-button').onclick = function(evt) { 160 OptionsPage.navigateToPage('pointer-overlay'); 161 }; 162 } 163 164 // Search section. 165 $('manage-default-search-engines').onclick = function(event) { 166 OptionsPage.navigateToPage('searchEngines'); 167 chrome.send('coreOptionsUserMetricsAction', 168 ['Options_ManageSearchEngines']); 169 }; 170 $('default-search-engine').addEventListener('change', 171 this.setDefaultSearchEngine_); 172 173 // Users section. 174 if (loadTimeData.valueExists('profilesInfo')) { 175 $('profiles-section').hidden = false; 176 177 var profilesList = $('profiles-list'); 178 options.browser_options.ProfileList.decorate(profilesList); 179 profilesList.autoExpands = true; 180 181 // The profiles info data in |loadTimeData| might be stale. 182 this.setProfilesInfo_(loadTimeData.getValue('profilesInfo')); 183 chrome.send('requestProfilesInfo'); 184 185 profilesList.addEventListener('change', 186 this.setProfileViewButtonsStatus_); 187 $('profiles-create').onclick = function(event) { 188 ManageProfileOverlay.showCreateDialog(); 189 }; 190 if (OptionsPage.isSettingsApp()) { 191 $('profiles-app-list-switch').onclick = function(event) { 192 var selectedProfile = self.getSelectedProfileItem_(); 193 chrome.send('switchAppListProfile', [selectedProfile.filePath]); 194 }; 195 } 196 $('profiles-manage').onclick = function(event) { 197 ManageProfileOverlay.showManageDialog(); 198 }; 199 $('profiles-delete').onclick = function(event) { 200 var selectedProfile = self.getSelectedProfileItem_(); 201 if (selectedProfile) 202 ManageProfileOverlay.showDeleteDialog(selectedProfile); 203 }; 204 if (loadTimeData.getBoolean('profileIsManaged')) { 205 $('profiles-create').disabled = true; 206 $('profiles-delete').disabled = true; 207 $('profiles-list').canDeleteItems = false; 208 } 209 } 210 211 if (cr.isChromeOS) { 212 if (!UIAccountTweaks.loggedInAsGuest()) { 213 $('account-picture-wrapper').onclick = function(event) { 214 OptionsPage.navigateToPage('changePicture'); 215 }; 216 } 217 218 // Username (canonical email) of the currently logged in user or 219 // |kGuestUser| if a guest session is active. 220 this.username_ = loadTimeData.getString('username'); 221 222 this.updateAccountPicture_(); 223 224 $('account-picture-wrapper').oncontextmenu = function(e) { 225 e.preventDefault(); 226 }; 227 228 $('manage-accounts-button').onclick = function(event) { 229 OptionsPage.navigateToPage('accounts'); 230 chrome.send('coreOptionsUserMetricsAction', 231 ['Options_ManageAccounts']); 232 }; 233 } else { 234 $('import-data').onclick = function(event) { 235 ImportDataOverlay.show(); 236 chrome.send('coreOptionsUserMetricsAction', ['Import_ShowDlg']); 237 }; 238 239 if ($('themes-native-button')) { 240 $('themes-native-button').onclick = function(event) { 241 chrome.send('themesSetNative'); 242 }; 243 } 244 } 245 246 // Default browser section. 247 if (!cr.isChromeOS) { 248 $('set-as-default-browser').onclick = function(event) { 249 chrome.send('becomeDefaultBrowser'); 250 }; 251 252 $('auto-launch').onclick = this.handleAutoLaunchChanged_; 253 } 254 255 // Privacy section. 256 $('privacyContentSettingsButton').onclick = function(event) { 257 OptionsPage.navigateToPage('content'); 258 OptionsPage.showTab($('cookies-nav-tab')); 259 chrome.send('coreOptionsUserMetricsAction', 260 ['Options_ContentSettings']); 261 }; 262 $('privacyClearDataButton').onclick = function(event) { 263 OptionsPage.navigateToPage('clearBrowserData'); 264 chrome.send('coreOptionsUserMetricsAction', ['Options_ClearData']); 265 }; 266 $('privacyClearDataButton').hidden = OptionsPage.isSettingsApp(); 267 // 'metricsReportingEnabled' element is only present on Chrome branded 268 // builds. 269 if ($('metricsReportingEnabled')) { 270 $('metricsReportingEnabled').onclick = function(event) { 271 chrome.send('metricsReportingCheckboxAction', 272 [String(event.currentTarget.checked)]); 273 }; 274 } 275 276 // Bluetooth (CrOS only). 277 if (cr.isChromeOS) { 278 options.system.bluetooth.BluetoothDeviceList.decorate( 279 $('bluetooth-paired-devices-list')); 280 281 $('bluetooth-add-device').onclick = 282 this.handleAddBluetoothDevice_.bind(this); 283 284 $('enable-bluetooth').onchange = function(event) { 285 var state = $('enable-bluetooth').checked; 286 chrome.send('bluetoothEnableChange', [Boolean(state)]); 287 }; 288 289 $('bluetooth-reconnect-device').onclick = function(event) { 290 var device = $('bluetooth-paired-devices-list').selectedItem; 291 var address = device.address; 292 chrome.send('updateBluetoothDevice', [address, 'connect']); 293 OptionsPage.closeOverlay(); 294 }; 295 296 $('bluetooth-reconnect-device').onmousedown = function(event) { 297 // Prevent 'blur' event, which would reset the list selection, 298 // thereby disabling the apply button. 299 event.preventDefault(); 300 }; 301 302 $('bluetooth-paired-devices-list').addEventListener('change', 303 function() { 304 var item = $('bluetooth-paired-devices-list').selectedItem; 305 var disabled = !item || item.connected || !item.connectable; 306 $('bluetooth-reconnect-device').disabled = disabled; 307 }); 308 } 309 310 // Passwords and Forms section. 311 $('autofill-settings').onclick = function(event) { 312 OptionsPage.navigateToPage('autofill'); 313 chrome.send('coreOptionsUserMetricsAction', 314 ['Options_ShowAutofillSettings']); 315 }; 316 $('manage-passwords').onclick = function(event) { 317 OptionsPage.navigateToPage('passwords'); 318 OptionsPage.showTab($('passwords-nav-tab')); 319 chrome.send('coreOptionsUserMetricsAction', 320 ['Options_ShowPasswordManager']); 321 }; 322 if (cr.isChromeOS && UIAccountTweaks.loggedInAsGuest()) { 323 // Disable and turn off Autofill in guest mode. 324 var autofillEnabled = $('autofill-enabled'); 325 autofillEnabled.disabled = true; 326 autofillEnabled.checked = false; 327 cr.dispatchSimpleEvent(autofillEnabled, 'change'); 328 $('autofill-settings').disabled = true; 329 330 // Disable and turn off Password Manager in guest mode. 331 var passwordManagerEnabled = $('password-manager-enabled'); 332 passwordManagerEnabled.disabled = true; 333 passwordManagerEnabled.checked = false; 334 cr.dispatchSimpleEvent(passwordManagerEnabled, 'change'); 335 $('manage-passwords').disabled = true; 336 } 337 338 if (cr.isMac) { 339 $('mac-passwords-warning').hidden = 340 !loadTimeData.getBoolean('multiple_profiles'); 341 } 342 343 // Network section. 344 if (!cr.isChromeOS) { 345 $('proxiesConfigureButton').onclick = function(event) { 346 chrome.send('showNetworkProxySettings'); 347 }; 348 } 349 350 // Web Content section. 351 $('fontSettingsCustomizeFontsButton').onclick = function(event) { 352 OptionsPage.navigateToPage('fonts'); 353 chrome.send('coreOptionsUserMetricsAction', ['Options_FontSettings']); 354 }; 355 $('defaultFontSize').onchange = function(event) { 356 var value = event.target.options[event.target.selectedIndex].value; 357 Preferences.setIntegerPref( 358 'webkit.webprefs.default_fixed_font_size', 359 value - OptionsPage.SIZE_DIFFERENCE_FIXED_STANDARD, true); 360 chrome.send('defaultFontSizeAction', [String(value)]); 361 }; 362 $('defaultZoomFactor').onchange = function(event) { 363 chrome.send('defaultZoomFactorAction', 364 [String(event.target.options[event.target.selectedIndex].value)]); 365 }; 366 367 // Languages section. 368 var showLanguageOptions = function(event) { 369 OptionsPage.navigateToPage('languages'); 370 chrome.send('coreOptionsUserMetricsAction', 371 ['Options_LanuageAndSpellCheckSettings']); 372 }; 373 $('language-button').onclick = showLanguageOptions; 374 $('manage-languages').onclick = showLanguageOptions; 375 376 if (!loadTimeData.getBoolean('enableTranslateSettings')) 377 $('manage-languages').hidden = true; 378 379 // Downloads section. 380 Preferences.getInstance().addEventListener('download.default_directory', 381 this.onDefaultDownloadDirectoryChanged_.bind(this)); 382 $('downloadLocationChangeButton').onclick = function(event) { 383 chrome.send('selectDownloadLocation'); 384 }; 385 if (!cr.isChromeOS) { 386 $('autoOpenFileTypesResetToDefault').onclick = function(event) { 387 chrome.send('autoOpenFileTypesAction'); 388 }; 389 } else { 390 $('disable-drive-row').hidden = 391 UIAccountTweaks.loggedInAsLocallyManagedUser(); 392 } 393 394 // HTTPS/SSL section. 395 if (cr.isWindows || cr.isMac) { 396 $('certificatesManageButton').onclick = function(event) { 397 chrome.send('showManageSSLCertificates'); 398 }; 399 } else { 400 $('certificatesManageButton').onclick = function(event) { 401 OptionsPage.navigateToPage('certificates'); 402 chrome.send('coreOptionsUserMetricsAction', 403 ['Options_ManageSSLCertificates']); 404 }; 405 } 406 407 // Cloud Print section. 408 // 'cloudPrintProxyEnabled' is true for Chrome branded builds on 409 // certain platforms, or could be enabled by a lab. 410 if (!cr.isChromeOS) { 411 $('cloudPrintConnectorSetupButton').onclick = function(event) { 412 if ($('cloudPrintManageButton').style.display == 'none') { 413 // Disable the button, set its text to the intermediate state. 414 $('cloudPrintConnectorSetupButton').textContent = 415 loadTimeData.getString('cloudPrintConnectorEnablingButton'); 416 $('cloudPrintConnectorSetupButton').disabled = true; 417 chrome.send('showCloudPrintSetupDialog'); 418 } else { 419 chrome.send('disableCloudPrintConnector'); 420 } 421 }; 422 } 423 $('cloudPrintManageButton').onclick = function(event) { 424 chrome.send('showCloudPrintManagePage'); 425 }; 426 427 // Accessibility section (CrOS only). 428 if (cr.isChromeOS) { 429 $('accessibility-spoken-feedback-check').onchange = function(event) { 430 chrome.send('spokenFeedbackChange', 431 [$('accessibility-spoken-feedback-check').checked]); 432 }; 433 434 $('accessibility-high-contrast-check').onchange = function(event) { 435 chrome.send('highContrastChange', 436 [$('accessibility-high-contrast-check').checked]); 437 }; 438 $('accessibility-sticky-keys').hidden = 439 !loadTimeData.getBoolean('enableStickyKeys'); 440 } 441 442 // Display management section (CrOS only). 443 if (cr.isChromeOS) { 444 $('display-options').onclick = function(event) { 445 OptionsPage.navigateToPage('display'); 446 chrome.send('coreOptionsUserMetricsAction', 447 ['Options_Display']); 448 }; 449 } 450 451 // Factory reset section (CrOS only). 452 if (cr.isChromeOS) { 453 $('factory-reset-restart').onclick = function(event) { 454 OptionsPage.navigateToPage('factoryResetData'); 455 }; 456 } 457 458 // System section. 459 if (!cr.isChromeOS) { 460 var updateGpuRestartButton = function() { 461 $('gpu-mode-reset-restart').hidden = 462 loadTimeData.getBoolean('gpuEnabledAtStart') == 463 $('gpu-mode-checkbox').checked; 464 }; 465 Preferences.getInstance().addEventListener( 466 $('gpu-mode-checkbox').getAttribute('pref'), 467 updateGpuRestartButton); 468 $('gpu-mode-reset-restart-button').onclick = function(event) { 469 chrome.send('restartBrowser'); 470 }; 471 updateGpuRestartButton(); 472 } 473 474 // Reset profile settings section. 475 $('reset-profile-settings-section').hidden = 476 !loadTimeData.getValue('enableResetProfileSettingsSection'); 477 $('reset-profile-settings').onclick = function(event) { 478 OptionsPage.navigateToPage('resetProfileSettings'); 479 }; 480 }, 481 482 /** @override */ 483 didShowPage: function() { 484 $('search-field').focus(); 485 }, 486 487 /** 488 * Called after all C++ UI handlers have called InitializePage to notify 489 * that initialization is complete. 490 * @private 491 */ 492 notifyInitializationComplete_: function() { 493 this.initializationComplete_ = true; 494 cr.dispatchSimpleEvent(document, 'initializationComplete'); 495 }, 496 497 /** 498 * Event listener for the 'session.restore_on_startup' pref. 499 * @param {Event} event The preference change event. 500 * @private 501 */ 502 onRestoreOnStartupChanged_: function(event) { 503 /** @const */ var showHomePageValue = 0; 504 505 if (event.value.value == showHomePageValue) { 506 // If the user previously selected "Show the homepage", the 507 // preference will already be migrated to "Open a specific page". So 508 // the only way to reach this code is if the 'restore on startup' 509 // preference is managed. 510 assert(event.value.controlledBy); 511 512 // Select "open the following pages" and lock down the list of URLs 513 // to reflect the intention of the policy. 514 $('startup-show-pages').checked = true; 515 StartupOverlay.getInstance().setControlsDisabled(true); 516 } else { 517 // Re-enable the controls in the startup overlay if necessary. 518 StartupOverlay.getInstance().updateControlStates(); 519 } 520 }, 521 522 /** 523 * Handler for messages sent from the main uber page. 524 * @param {Event} e The 'message' event from the uber page. 525 * @private 526 */ 527 handleWindowMessage_: function(e) { 528 if (e.data.method == 'frameSelected') 529 $('search-field').focus(); 530 }, 531 532 /** 533 * Shows the given section. 534 * @param {HTMLElement} section The section to be shown. 535 * @param {HTMLElement} container The container for the section. Must be 536 * inside of |section|. 537 * @param {boolean} animate Indicate if the expansion should be animated. 538 * @private 539 */ 540 showSection_: function(section, container, animate) { 541 if (animate) 542 this.addTransitionEndListener_(section); 543 544 // Unhide 545 section.hidden = false; 546 547 var expander = function() { 548 // Reveal the section using a WebKit transition if animating. 549 if (animate) { 550 section.classList.add('sliding'); 551 section.style.height = container.offsetHeight + 'px'; 552 } else { 553 section.style.height = 'auto'; 554 } 555 }; 556 557 // Delay starting the transition if animating so that hidden change will 558 // be processed. 559 if (animate) 560 setTimeout(expander, 0); 561 else 562 expander(); 563 }, 564 565 /** 566 * Shows the given section, with animation. 567 * @param {HTMLElement} section The section to be shown. 568 * @param {HTMLElement} container The container for the section. Must be 569 * inside of |section|. 570 * @private 571 */ 572 showSectionWithAnimation_: function(section, container) { 573 this.showSection_(section, container, /*animate */ true); 574 }, 575 576 /** 577 * See showSectionWithAnimation_. 578 */ 579 hideSectionWithAnimation_: function(section, container) { 580 this.addTransitionEndListener_(section); 581 582 // Before we start hiding the section, we need to set 583 // the height to a pixel value. 584 section.style.height = container.offsetHeight + 'px'; 585 586 // Delay starting the transition so that the height change will be 587 // processed. 588 setTimeout(function() { 589 // Hide the section using a WebKit transition. 590 section.classList.add('sliding'); 591 section.style.height = ''; 592 }, 0); 593 }, 594 595 /** 596 * See showSectionWithAnimation_. 597 */ 598 toggleSectionWithAnimation_: function(section, container) { 599 if (section.style.height == '') 600 this.showSectionWithAnimation_(section, container); 601 else 602 this.hideSectionWithAnimation_(section, container); 603 }, 604 605 /** 606 * Scrolls the settings page to make the section visible auto-expanding 607 * advanced settings if required. The transition is not animated. This 608 * method is used to ensure that a section associated with an overlay 609 * is visible when the overlay is closed. 610 * @param {!Element} section The section to make visible. 611 * @private 612 */ 613 scrollToSection_: function(section) { 614 var advancedSettings = $('advanced-settings'); 615 var container = $('advanced-settings-container'); 616 if (advancedSettings.hidden && section.parentNode == container) { 617 this.showSection_($('advanced-settings'), 618 $('advanced-settings-container'), 619 /* animate */ false); 620 this.updateAdvancedSettingsExpander_(); 621 } 622 623 if (!this.initializationComplete_) { 624 var self = this; 625 var callback = function() { 626 document.removeEventListener('initializationComplete', callback); 627 self.scrollToSection_(section); 628 }; 629 document.addEventListener('initializationComplete', callback); 630 return; 631 } 632 633 var pageContainer = $('page-container'); 634 var pageTop = parseFloat(pageContainer.style.top); 635 var topSection = document.querySelector('#page-container section'); 636 var pageHeight = document.body.scrollHeight - topSection.offsetTop; 637 var sectionTop = section.offsetTop; 638 var sectionHeight = section.offsetHeight; 639 var marginBottom = window.getComputedStyle(section).marginBottom; 640 if (marginBottom) 641 sectionHeight += parseFloat(marginBottom); 642 if (pageHeight - pageTop < sectionTop + sectionHeight) { 643 pageContainer.oldScrollTop = sectionTop + sectionHeight - pageHeight; 644 var verticalPosition = pageContainer.getBoundingClientRect().top - 645 pageContainer.oldScrollTop; 646 pageContainer.style.top = verticalPosition + 'px'; 647 } 648 }, 649 650 /** 651 * Adds a |webkitTransitionEnd| listener to the given section so that 652 * it can be animated. The listener will only be added to a given section 653 * once, so this can be called as multiple times. 654 * @param {HTMLElement} section The section to be animated. 655 * @private 656 */ 657 addTransitionEndListener_: function(section) { 658 if (section.hasTransitionEndListener_) 659 return; 660 661 section.addEventListener('webkitTransitionEnd', 662 this.onTransitionEnd_.bind(this)); 663 section.hasTransitionEndListener_ = true; 664 }, 665 666 /** 667 * Called after an animation transition has ended. 668 * @private 669 */ 670 onTransitionEnd_: function(event) { 671 if (event.propertyName != 'height') 672 return; 673 674 var section = event.target; 675 676 // Disable WebKit transitions. 677 section.classList.remove('sliding'); 678 679 if (section.style.height == '') { 680 // Hide the content so it can't get tab focus. 681 section.hidden = true; 682 } else { 683 // Set the section height to 'auto' to allow for size changes 684 // (due to font change or dynamic content). 685 section.style.height = 'auto'; 686 } 687 }, 688 689 updateAdvancedSettingsExpander_: function() { 690 var expander = $('advanced-settings-expander'); 691 if ($('advanced-settings').style.height == '') 692 expander.textContent = loadTimeData.getString('showAdvancedSettings'); 693 else 694 expander.textContent = loadTimeData.getString('hideAdvancedSettings'); 695 }, 696 697 /** 698 * Updates the sync section with the given state. 699 * @param {Object} syncData A bunch of data records that describe the status 700 * of the sync system. 701 * @private 702 */ 703 updateSyncState_: function(syncData) { 704 if (!syncData.signinAllowed && 705 (!syncData.supervisedUser || !cr.isChromeOS)) { 706 $('sync-section').hidden = true; 707 return; 708 } 709 710 $('sync-section').hidden = false; 711 712 var subSection = $('sync-section').firstChild; 713 while (subSection) { 714 if (subSection.nodeType == Node.ELEMENT_NODE) 715 subSection.hidden = syncData.supervisedUser; 716 subSection = subSection.nextSibling; 717 } 718 719 if (syncData.supervisedUser) { 720 $('account-picture-wrapper').hidden = false; 721 $('sync-general').hidden = false; 722 $('sync-status').hidden = true; 723 return; 724 } 725 726 // If the user gets signed out while the advanced sync settings dialog is 727 // visible, say, due to a dashboard clear, close the dialog. 728 // Note: SyncSetupOverlay.closeOverlay is a no-op if the overlay is 729 // already hidden. 730 if (this.signedIn_ && !syncData.signedIn) 731 SyncSetupOverlay.closeOverlay(); 732 733 this.signedIn_ = syncData.signedIn; 734 735 // Display the "advanced settings" button if we're signed in and sync is 736 // not managed/disabled. If the user is signed in, but sync is disabled, 737 // this button is used to re-enable sync. 738 var customizeSyncButton = $('customize-sync'); 739 customizeSyncButton.hidden = !this.signedIn_ || 740 syncData.managed || 741 !syncData.syncSystemEnabled; 742 743 // Only modify the customize button's text if the new text is different. 744 // Otherwise, it can affect search-highlighting in the settings page. 745 // See http://crbug.com/268265. 746 var customizeSyncButtonNewText = syncData.setupCompleted ? 747 loadTimeData.getString('customizeSync') : 748 loadTimeData.getString('syncButtonTextStart'); 749 if (customizeSyncButton.textContent != customizeSyncButtonNewText) 750 customizeSyncButton.textContent = customizeSyncButtonNewText; 751 752 // Disable the "sign in" button if we're currently signing in, or if we're 753 // already signed in and signout is not allowed. 754 var signInButton = $('start-stop-sync'); 755 signInButton.disabled = syncData.setupInProgress || 756 !syncData.signoutAllowed; 757 if (!syncData.signoutAllowed) 758 $('start-stop-sync-indicator').setAttribute('controlled-by', 'policy'); 759 else 760 $('start-stop-sync-indicator').removeAttribute('controlled-by'); 761 762 // Hide the "sign in" button on Chrome OS, and show it on desktop Chrome. 763 signInButton.hidden = cr.isChromeOS; 764 765 signInButton.textContent = 766 this.signedIn_ ? 767 loadTimeData.getString('syncButtonTextStop') : 768 syncData.setupInProgress ? 769 loadTimeData.getString('syncButtonTextInProgress') : 770 loadTimeData.getString('syncButtonTextSignIn'); 771 $('start-stop-sync-indicator').hidden = signInButton.hidden; 772 773 // TODO(estade): can this just be textContent? 774 $('sync-status-text').innerHTML = syncData.statusText; 775 var statusSet = syncData.statusText.length != 0; 776 $('sync-overview').hidden = statusSet; 777 $('sync-status').hidden = !statusSet; 778 779 $('sync-action-link').textContent = syncData.actionLinkText; 780 // Don't show the action link if it is empty or undefined. 781 $('sync-action-link').hidden = syncData.actionLinkText.length == 0; 782 $('sync-action-link').disabled = syncData.managed || 783 !syncData.syncSystemEnabled; 784 785 // On Chrome OS, sign out the user and sign in again to get fresh 786 // credentials on auth errors. 787 $('sync-action-link').onclick = function(event) { 788 if (cr.isChromeOS && syncData.hasError) 789 SyncSetupOverlay.doSignOutOnAuthError(); 790 else 791 SyncSetupOverlay.showSetupUI(); 792 }; 793 794 if (syncData.hasError) 795 $('sync-status').classList.add('sync-error'); 796 else 797 $('sync-status').classList.remove('sync-error'); 798 799 customizeSyncButton.disabled = syncData.hasUnrecoverableError; 800 // Move #enable-auto-login-checkbox to a different location on CrOS. 801 if (cr.isChromeOs) { 802 $('sync-general').insertBefore($('sync-status').nextSibling, 803 $('enable-auto-login-checkbox')); 804 } 805 $('enable-auto-login-checkbox').hidden = !syncData.autoLoginVisible; 806 }, 807 808 /** 809 * Get the start/stop sync button DOM element. Used for testing. 810 * @return {DOMElement} The start/stop sync button. 811 * @private 812 */ 813 getStartStopSyncButton_: function() { 814 return $('start-stop-sync'); 815 }, 816 817 /** 818 * Event listener for the 'show home button' preference. Shows/hides the 819 * UI for changing the home page with animation, unless this is the first 820 * time this function is called, in which case there is no animation. 821 * @param {Event} event The preference change event. 822 */ 823 onShowHomeButtonChanged_: function(event) { 824 var section = $('change-home-page-section'); 825 if (this.onShowHomeButtonChangedCalled_) { 826 var container = $('change-home-page-section-container'); 827 if (event.value.value) 828 this.showSectionWithAnimation_(section, container); 829 else 830 this.hideSectionWithAnimation_(section, container); 831 } else { 832 section.hidden = !event.value.value; 833 this.onShowHomeButtonChangedCalled_ = true; 834 } 835 }, 836 837 /** 838 * Event listener for the 'homepage is NTP' preference. Updates the label 839 * next to the 'Change' button. 840 * @param {Event} event The preference change event. 841 */ 842 onHomePageIsNtpChanged_: function(event) { 843 if (!event.value.uncommitted) { 844 $('home-page-url').hidden = event.value.value; 845 $('home-page-ntp').hidden = !event.value.value; 846 } 847 }, 848 849 /** 850 * Event listener for changes to the homepage preference. Updates the label 851 * next to the 'Change' button. 852 * @param {Event} event The preference change event. 853 */ 854 onHomePageChanged_: function(event) { 855 if (!event.value.uncommitted) 856 $('home-page-url').textContent = this.stripHttp_(event.value.value); 857 }, 858 859 /** 860 * Removes the 'http://' from a URL, like the omnibox does. If the string 861 * doesn't start with 'http://' it is returned unchanged. 862 * @param {string} url The url to be processed 863 * @return {string} The url with the 'http://' removed. 864 */ 865 stripHttp_: function(url) { 866 return url.replace(/^http:\/\//, ''); 867 }, 868 869 /** 870 * Shows the autoLaunch preference and initializes its checkbox value. 871 * @param {bool} enabled Whether autolaunch is enabled or or not. 872 * @private 873 */ 874 updateAutoLaunchState_: function(enabled) { 875 $('auto-launch-option').hidden = false; 876 $('auto-launch').checked = enabled; 877 }, 878 879 /** 880 * Called when the value of the download.default_directory preference 881 * changes. 882 * @param {Event} event Change event. 883 * @private 884 */ 885 onDefaultDownloadDirectoryChanged_: function(event) { 886 $('downloadLocationPath').value = event.value.value; 887 if (cr.isChromeOS) { 888 // On ChromeOS, replace /special/drive with Drive for drive paths, and 889 // /home/chronos/user/Downloads with Downloads for local files. 890 // Also replace '/' with ' \u203a ' (angled quote sign) everywhere. 891 var path = $('downloadLocationPath').value; 892 path = path.replace(/^\/special\/drive\/root/, 'Google Drive'); 893 path = path.replace(/^\/home\/chronos\/user\//, ''); 894 path = path.replace(/\//g, ' \u203a '); 895 $('downloadLocationPath').value = path; 896 } 897 if (event.value.disabled) 898 $('download-location-label').classList.add('disabled'); 899 else 900 $('download-location-label').classList.remove('disabled'); 901 $('downloadLocationChangeButton').disabled = event.value.disabled; 902 }, 903 904 /** 905 * Update the Default Browsers section based on the current state. 906 * @param {string} statusString Description of the current default state. 907 * @param {boolean} isDefault Whether or not the browser is currently 908 * default. 909 * @param {boolean} canBeDefault Whether or not the browser can be default. 910 * @private 911 */ 912 updateDefaultBrowserState_: function(statusString, isDefault, 913 canBeDefault) { 914 if (!cr.isChromeOS) { 915 var label = $('default-browser-state'); 916 label.textContent = statusString; 917 918 $('set-as-default-browser').hidden = !canBeDefault || isDefault; 919 } 920 }, 921 922 /** 923 * Clears the search engine popup. 924 * @private 925 */ 926 clearSearchEngines_: function() { 927 $('default-search-engine').textContent = ''; 928 }, 929 930 /** 931 * Updates the search engine popup with the given entries. 932 * @param {Array} engines List of available search engines. 933 * @param {number} defaultValue The value of the current default engine. 934 * @param {boolean} defaultManaged Whether the default search provider is 935 * managed. If true, the default search provider can't be changed. 936 * @private 937 */ 938 updateSearchEngines_: function(engines, defaultValue, defaultManaged) { 939 this.clearSearchEngines_(); 940 engineSelect = $('default-search-engine'); 941 engineSelect.disabled = defaultManaged; 942 if (defaultManaged && defaultValue == -1) 943 return; 944 engineCount = engines.length; 945 var defaultIndex = -1; 946 for (var i = 0; i < engineCount; i++) { 947 var engine = engines[i]; 948 var option = new Option(engine.name, engine.index); 949 if (defaultValue == option.value) 950 defaultIndex = i; 951 engineSelect.appendChild(option); 952 } 953 if (defaultIndex >= 0) 954 engineSelect.selectedIndex = defaultIndex; 955 }, 956 957 /** 958 * Set the default search engine based on the popup selection. 959 * @private 960 */ 961 setDefaultSearchEngine_: function() { 962 var engineSelect = $('default-search-engine'); 963 var selectedIndex = engineSelect.selectedIndex; 964 if (selectedIndex >= 0) { 965 var selection = engineSelect.options[selectedIndex]; 966 chrome.send('setDefaultSearchEngine', [String(selection.value)]); 967 } 968 }, 969 970 /** 971 * Sets or clear whether Chrome should Auto-launch on computer startup. 972 * @private 973 */ 974 handleAutoLaunchChanged_: function() { 975 chrome.send('toggleAutoLaunch', [$('auto-launch').checked]); 976 }, 977 978 /** 979 * Get the selected profile item from the profile list. This also works 980 * correctly if the list is not displayed. 981 * @return {Object} the profile item object, or null if nothing is selected. 982 * @private 983 */ 984 getSelectedProfileItem_: function() { 985 var profilesList = $('profiles-list'); 986 if (profilesList.hidden) { 987 if (profilesList.dataModel.length > 0) 988 return profilesList.dataModel.item(0); 989 } else { 990 return profilesList.selectedItem; 991 } 992 return null; 993 }, 994 995 /** 996 * Helper function to set the status of profile view buttons to disabled or 997 * enabled, depending on the number of profiles and selection status of the 998 * profiles list. 999 * @private 1000 */ 1001 setProfileViewButtonsStatus_: function() { 1002 var profilesList = $('profiles-list'); 1003 var selectedProfile = profilesList.selectedItem; 1004 var hasSelection = selectedProfile != null; 1005 var hasSingleProfile = profilesList.dataModel.length == 1; 1006 var isManaged = loadTimeData.getBoolean('profileIsManaged'); 1007 $('profiles-manage').disabled = !hasSelection || 1008 !selectedProfile.isCurrentProfile; 1009 if (hasSelection && !selectedProfile.isCurrentProfile) 1010 $('profiles-manage').title = loadTimeData.getString('currentUserOnly'); 1011 else 1012 $('profiles-manage').title = ''; 1013 $('profiles-delete').disabled = isManaged || 1014 (!hasSelection && !hasSingleProfile); 1015 if (OptionsPage.isSettingsApp()) { 1016 $('profiles-app-list-switch').disabled = !hasSelection || 1017 selectedProfile.isCurrentProfile; 1018 } 1019 var importData = $('import-data'); 1020 if (importData) { 1021 importData.disabled = $('import-data').disabled = hasSelection && 1022 !selectedProfile.isCurrentProfile; 1023 } 1024 }, 1025 1026 /** 1027 * Display the correct dialog layout, depending on how many profiles are 1028 * available. 1029 * @param {number} numProfiles The number of profiles to display. 1030 * @private 1031 */ 1032 setProfileViewSingle_: function(numProfiles) { 1033 var hasSingleProfile = numProfiles == 1; 1034 $('profiles-list').hidden = hasSingleProfile; 1035 $('profiles-single-message').hidden = !hasSingleProfile; 1036 $('profiles-manage').hidden = 1037 hasSingleProfile || OptionsPage.isSettingsApp(); 1038 $('profiles-delete').textContent = hasSingleProfile ? 1039 loadTimeData.getString('profilesDeleteSingle') : 1040 loadTimeData.getString('profilesDelete'); 1041 if (OptionsPage.isSettingsApp()) 1042 $('profiles-app-list-switch').hidden = hasSingleProfile; 1043 }, 1044 1045 /** 1046 * Adds all |profiles| to the list. 1047 * @param {Array.<Object>} profiles An array of profile info objects. 1048 * each object is of the form: 1049 * profileInfo = { 1050 * name: "Profile Name", 1051 * iconURL: "chrome://path/to/icon/image", 1052 * filePath: "/path/to/profile/data/on/disk", 1053 * isCurrentProfile: false 1054 * }; 1055 * @private 1056 */ 1057 setProfilesInfo_: function(profiles) { 1058 this.setProfileViewSingle_(profiles.length); 1059 // add it to the list, even if the list is hidden so we can access it 1060 // later. 1061 $('profiles-list').dataModel = new ArrayDataModel(profiles); 1062 1063 // Received new data. If showing the "manage" overlay, keep it up to 1064 // date. If showing the "delete" overlay, close it. 1065 if (ManageProfileOverlay.getInstance().visible && 1066 !$('manage-profile-overlay-manage').hidden) { 1067 ManageProfileOverlay.showManageDialog(); 1068 } else { 1069 ManageProfileOverlay.getInstance().visible = false; 1070 } 1071 1072 this.setProfileViewButtonsStatus_(); 1073 }, 1074 1075 /** 1076 * Reports a local error (e.g., disk full) to the "create" overlay during 1077 * profile creation. 1078 * @private 1079 */ 1080 showCreateProfileLocalError_: function() { 1081 CreateProfileOverlay.onLocalError(); 1082 }, 1083 1084 /** 1085 * Reports a remote error (e.g., a network error during managed-user 1086 * registration) to the "create" overlay during profile creation. 1087 * @private 1088 */ 1089 showCreateProfileRemoteError_: function() { 1090 CreateProfileOverlay.onRemoteError(); 1091 }, 1092 1093 /** 1094 * Reports successful profile creation to the "create" overlay. 1095 * @param {Object} profileInfo An object of the form: 1096 * profileInfo = { 1097 * name: "Profile Name", 1098 * filePath: "/path/to/profile/data/on/disk" 1099 * isManaged: (true|false), 1100 * }; 1101 * @private 1102 */ 1103 showCreateProfileSuccess_: function(profileInfo) { 1104 CreateProfileOverlay.onSuccess(profileInfo); 1105 }, 1106 1107 /** 1108 * Returns the currently active profile for this browser window. 1109 * @return {Object} A profile info object. 1110 * @private 1111 */ 1112 getCurrentProfile_: function() { 1113 for (var i = 0; i < $('profiles-list').dataModel.length; i++) { 1114 var profile = $('profiles-list').dataModel.item(i); 1115 if (profile.isCurrentProfile) 1116 return profile; 1117 } 1118 1119 assert(false, 1120 'There should always be a current profile, but none found.'); 1121 }, 1122 1123 setNativeThemeButtonEnabled_: function(enabled) { 1124 var button = $('themes-native-button'); 1125 if (button) 1126 button.disabled = !enabled; 1127 }, 1128 1129 setThemesResetButtonEnabled_: function(enabled) { 1130 $('themes-reset').disabled = !enabled; 1131 }, 1132 1133 /** 1134 * (Re)loads IMG element with current user account picture. 1135 * @private 1136 */ 1137 updateAccountPicture_: function() { 1138 var picture = $('account-picture'); 1139 if (picture) { 1140 picture.src = 'chrome://userimage/' + this.username_ + '?id=' + 1141 Date.now(); 1142 } 1143 }, 1144 1145 /** 1146 * Handle the 'add device' button click. 1147 * @private 1148 */ 1149 handleAddBluetoothDevice_: function() { 1150 chrome.send('findBluetoothDevices'); 1151 OptionsPage.showPageByName('bluetooth', false); 1152 }, 1153 1154 /** 1155 * Enables factory reset section. 1156 * @private 1157 */ 1158 enableFactoryResetSection_: function() { 1159 $('factory-reset-section').hidden = false; 1160 }, 1161 1162 /** 1163 * Set the checked state of the metrics reporting checkbox. 1164 * @private 1165 */ 1166 setMetricsReportingCheckboxState_: function(checked, disabled) { 1167 $('metricsReportingEnabled').checked = checked; 1168 $('metricsReportingEnabled').disabled = disabled; 1169 }, 1170 1171 /** 1172 * @private 1173 */ 1174 setMetricsReportingSettingVisibility_: function(visible) { 1175 if (visible) 1176 $('metricsReportingSetting').style.display = 'block'; 1177 else 1178 $('metricsReportingSetting').style.display = 'none'; 1179 }, 1180 1181 /** 1182 * Set the visibility of the password generation checkbox. 1183 * @private 1184 */ 1185 setPasswordGenerationSettingVisibility_: function(visible) { 1186 if (visible) 1187 $('password-generation-checkbox').style.display = 'block'; 1188 else 1189 $('password-generation-checkbox').style.display = 'none'; 1190 }, 1191 1192 /** 1193 * Set the font size selected item. This item actually reflects two 1194 * preferences: the default font size and the default fixed font size. 1195 * 1196 * @param {Object} pref Information about the font size preferences. 1197 * @param {number} pref.value The value of the default font size pref. 1198 * @param {boolean} pref.disabled True if either pref not user modifiable. 1199 * @param {string} pref.controlledBy The source of the pref value(s) if 1200 * either pref is currently not controlled by the user. 1201 * @private 1202 */ 1203 setFontSize_: function(pref) { 1204 var selectCtl = $('defaultFontSize'); 1205 selectCtl.disabled = pref.disabled; 1206 // Create a synthetic pref change event decorated as 1207 // CoreOptionsHandler::CreateValueForPref() does. 1208 var event = new cr.Event('synthetic-font-size'); 1209 event.value = { 1210 value: pref.value, 1211 controlledBy: pref.controlledBy, 1212 disabled: pref.disabled 1213 }; 1214 $('font-size-indicator').handlePrefChange(event); 1215 1216 for (var i = 0; i < selectCtl.options.length; i++) { 1217 if (selectCtl.options[i].value == pref.value) { 1218 selectCtl.selectedIndex = i; 1219 if ($('Custom')) 1220 selectCtl.remove($('Custom').index); 1221 return; 1222 } 1223 } 1224 1225 // Add/Select Custom Option in the font size label list. 1226 if (!$('Custom')) { 1227 var option = new Option(loadTimeData.getString('fontSizeLabelCustom'), 1228 -1, false, true); 1229 option.setAttribute('id', 'Custom'); 1230 selectCtl.add(option); 1231 } 1232 $('Custom').selected = true; 1233 }, 1234 1235 /** 1236 * Populate the page zoom selector with values received from the caller. 1237 * @param {Array} items An array of items to populate the selector. 1238 * each object is an array with three elements as follows: 1239 * 0: The title of the item (string). 1240 * 1: The value of the item (number). 1241 * 2: Whether the item should be selected (boolean). 1242 * @private 1243 */ 1244 setupPageZoomSelector_: function(items) { 1245 var element = $('defaultZoomFactor'); 1246 1247 // Remove any existing content. 1248 element.textContent = ''; 1249 1250 // Insert new child nodes into select element. 1251 var value, title, selected; 1252 for (var i = 0; i < items.length; i++) { 1253 title = items[i][0]; 1254 value = items[i][1]; 1255 selected = items[i][2]; 1256 element.appendChild(new Option(title, value, false, selected)); 1257 } 1258 }, 1259 1260 /** 1261 * Shows/hides the autoOpenFileTypesResetToDefault button and label, with 1262 * animation. 1263 * @param {boolean} display Whether to show the button and label or not. 1264 * @private 1265 */ 1266 setAutoOpenFileTypesDisplayed_: function(display) { 1267 if (cr.isChromeOS) 1268 return; 1269 1270 if ($('advanced-settings').hidden) { 1271 // If the Advanced section is hidden, don't animate the transition. 1272 $('auto-open-file-types-section').hidden = !display; 1273 } else { 1274 if (display) { 1275 this.showSectionWithAnimation_( 1276 $('auto-open-file-types-section'), 1277 $('auto-open-file-types-container')); 1278 } else { 1279 this.hideSectionWithAnimation_( 1280 $('auto-open-file-types-section'), 1281 $('auto-open-file-types-container')); 1282 } 1283 } 1284 }, 1285 1286 /** 1287 * Set the enabled state for the proxy settings button. 1288 * @private 1289 */ 1290 setupProxySettingsSection_: function(disabled, extensionControlled) { 1291 if (!cr.isChromeOS) { 1292 $('proxiesConfigureButton').disabled = disabled; 1293 $('proxiesLabel').textContent = 1294 loadTimeData.getString(extensionControlled ? 1295 'proxiesLabelExtension' : 'proxiesLabelSystem'); 1296 } 1297 }, 1298 1299 /** 1300 * Set the Cloud Print proxy UI to enabled, disabled, or processing. 1301 * @private 1302 */ 1303 setupCloudPrintConnectorSection_: function(disabled, label, allowed) { 1304 if (!cr.isChromeOS) { 1305 $('cloudPrintConnectorLabel').textContent = label; 1306 if (disabled || !allowed) { 1307 $('cloudPrintConnectorSetupButton').textContent = 1308 loadTimeData.getString('cloudPrintConnectorDisabledButton'); 1309 $('cloudPrintManageButton').style.display = 'none'; 1310 } else { 1311 $('cloudPrintConnectorSetupButton').textContent = 1312 loadTimeData.getString('cloudPrintConnectorEnabledButton'); 1313 $('cloudPrintManageButton').style.display = 'inline'; 1314 } 1315 $('cloudPrintConnectorSetupButton').disabled = !allowed; 1316 } 1317 }, 1318 1319 /** 1320 * @private 1321 */ 1322 removeCloudPrintConnectorSection_: function() { 1323 if (!cr.isChromeOS) { 1324 var connectorSectionElm = $('cloud-print-connector-section'); 1325 if (connectorSectionElm) 1326 connectorSectionElm.parentNode.removeChild(connectorSectionElm); 1327 } 1328 }, 1329 1330 /** 1331 * Set the initial state of the spoken feedback checkbox. 1332 * @private 1333 */ 1334 setSpokenFeedbackCheckboxState_: function(checked) { 1335 $('accessibility-spoken-feedback-check').checked = checked; 1336 }, 1337 1338 /** 1339 * Set the initial state of the high contrast checkbox. 1340 * @private 1341 */ 1342 setHighContrastCheckboxState_: function(checked) { 1343 $('accessibility-high-contrast-check').checked = checked; 1344 }, 1345 1346 /** 1347 * Set the initial state of the virtual keyboard checkbox. 1348 * @private 1349 */ 1350 setVirtualKeyboardCheckboxState_: function(checked) { 1351 // TODO(zork): Update UI 1352 }, 1353 1354 /** 1355 * Show/hide mouse settings slider. 1356 * @private 1357 */ 1358 showMouseControls_: function(show) { 1359 $('mouse-settings').hidden = !show; 1360 }, 1361 1362 /** 1363 * Show/hide touchpad-related settings. 1364 * @private 1365 */ 1366 showTouchpadControls_: function(show) { 1367 $('touchpad-settings').hidden = !show; 1368 $('accessibility-tap-dragging').hidden = !show; 1369 }, 1370 1371 /** 1372 * Activate the Bluetooth settings section on the System settings page. 1373 * @private 1374 */ 1375 showBluetoothSettings_: function() { 1376 $('bluetooth-devices').hidden = false; 1377 }, 1378 1379 /** 1380 * Dectivates the Bluetooth settings section from the System settings page. 1381 * @private 1382 */ 1383 hideBluetoothSettings_: function() { 1384 $('bluetooth-devices').hidden = true; 1385 }, 1386 1387 /** 1388 * Sets the state of the checkbox indicating if Bluetooth is turned on. The 1389 * state of the "Find devices" button and the list of discovered devices may 1390 * also be affected by a change to the state. 1391 * @param {boolean} checked Flag Indicating if Bluetooth is turned on. 1392 * @private 1393 */ 1394 setBluetoothState_: function(checked) { 1395 $('enable-bluetooth').checked = checked; 1396 $('bluetooth-paired-devices-list').parentNode.hidden = !checked; 1397 $('bluetooth-add-device').hidden = !checked; 1398 $('bluetooth-reconnect-device').hidden = !checked; 1399 // Flush list of previously discovered devices if bluetooth is turned off. 1400 if (!checked) { 1401 $('bluetooth-paired-devices-list').clear(); 1402 $('bluetooth-unpaired-devices-list').clear(); 1403 } else { 1404 chrome.send('getPairedBluetoothDevices'); 1405 } 1406 }, 1407 1408 /** 1409 * Adds an element to the list of available Bluetooth devices. If an element 1410 * with a matching address is found, the existing element is updated. 1411 * @param {{name: string, 1412 * address: string, 1413 * paired: boolean, 1414 * connected: boolean}} device 1415 * Decription of the Bluetooth device. 1416 * @private 1417 */ 1418 addBluetoothDevice_: function(device) { 1419 var list = $('bluetooth-unpaired-devices-list'); 1420 // Display the "connecting" (already paired or not yet paired) and the 1421 // paired devices in the same list. 1422 if (device.paired || device.connecting) { 1423 // Test to see if the device is currently in the unpaired list, in which 1424 // case it should be removed from that list. 1425 var index = $('bluetooth-unpaired-devices-list').find(device.address); 1426 if (index != undefined) 1427 $('bluetooth-unpaired-devices-list').deleteItemAtIndex(index); 1428 list = $('bluetooth-paired-devices-list'); 1429 } else { 1430 // Test to see if the device is currently in the paired list, in which 1431 // case it should be removed from that list. 1432 var index = $('bluetooth-paired-devices-list').find(device.address); 1433 if (index != undefined) 1434 $('bluetooth-paired-devices-list').deleteItemAtIndex(index); 1435 } 1436 list.appendDevice(device); 1437 1438 // One device can be in the process of pairing. If found, display 1439 // the Bluetooth pairing overlay. 1440 if (device.pairing) 1441 BluetoothPairing.showDialog(device); 1442 }, 1443 1444 /** 1445 * Removes an element from the list of available devices. 1446 * @param {string} address Unique address of the device. 1447 * @private 1448 */ 1449 removeBluetoothDevice_: function(address) { 1450 var index = $('bluetooth-unpaired-devices-list').find(address); 1451 if (index != undefined) { 1452 $('bluetooth-unpaired-devices-list').deleteItemAtIndex(index); 1453 } else { 1454 index = $('bluetooth-paired-devices-list').find(address); 1455 if (index != undefined) 1456 $('bluetooth-paired-devices-list').deleteItemAtIndex(index); 1457 } 1458 } 1459 }; 1460 1461 //Forward public APIs to private implementations. 1462 [ 1463 'addBluetoothDevice', 1464 'enableFactoryResetSection', 1465 'getCurrentProfile', 1466 'getStartStopSyncButton', 1467 'hideBluetoothSettings', 1468 'notifyInitializationComplete', 1469 'removeBluetoothDevice', 1470 'removeCloudPrintConnectorSection', 1471 'scrollToSection', 1472 'setAutoOpenFileTypesDisplayed', 1473 'setBluetoothState', 1474 'setFontSize', 1475 'setNativeThemeButtonEnabled', 1476 'setHighContrastCheckboxState', 1477 'setMetricsReportingCheckboxState', 1478 'setMetricsReportingSettingVisibility', 1479 'setPasswordGenerationSettingVisibility', 1480 'setProfilesInfo', 1481 'setSpokenFeedbackCheckboxState', 1482 'setThemesResetButtonEnabled', 1483 'setVirtualKeyboardCheckboxState', 1484 'setupCloudPrintConnectorSection', 1485 'setupPageZoomSelector', 1486 'setupProxySettingsSection', 1487 'showBluetoothSettings', 1488 'showCreateProfileLocalError', 1489 'showCreateProfileRemoteError', 1490 'showCreateProfileSuccess', 1491 'showMouseControls', 1492 'showTouchpadControls', 1493 'updateAccountPicture', 1494 'updateAutoLaunchState', 1495 'updateDefaultBrowserState', 1496 'updateSearchEngines', 1497 'updateStartupPages', 1498 'updateSyncState', 1499 ].forEach(function(name) { 1500 BrowserOptions[name] = function() { 1501 var instance = BrowserOptions.getInstance(); 1502 return instance[name + '_'].apply(instance, arguments); 1503 }; 1504 }); 1505 1506 if (cr.isChromeOS) { 1507 /** 1508 * Returns username (canonical email) of the user logged in (ChromeOS only). 1509 * @return {string} user email. 1510 */ 1511 // TODO(jhawkins): Investigate the use case for this method. 1512 BrowserOptions.getLoggedInUsername = function() { 1513 return BrowserOptions.getInstance().username_; 1514 }; 1515 } 1516 1517 // Export 1518 return { 1519 BrowserOptions: BrowserOptions 1520 }; 1521 }); 1522