1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 cr.define('options', function() {
6 var OptionsPage = options.OptionsPage;
7 var ArrayDataModel = cr.ui.ArrayDataModel;
8 var RepeatingButton = cr.ui.RepeatingButton;
9 var HotwordSearchSettingIndicator = options.HotwordSearchSettingIndicator;
12 // BrowserOptions class
13 // Encapsulated handling of browser options page.
15 function BrowserOptions() {
16 OptionsPage.call(this, 'settings', loadTimeData.getString('settingsTitle'),
20 cr.addSingletonGetter(BrowserOptions);
23 * @param {HTMLElement} section The section to show or hide.
24 * @return {boolean} Whether the section should be shown.
27 BrowserOptions.shouldShowSection_ = function(section) {
28 // If the section is hidden or hiding, it should be shown.
29 return section.style.height == '' || section.style.height == '0px';
32 BrowserOptions.prototype = {
33 __proto__: options.OptionsPage.prototype,
36 * Keeps track of whether the user is signed in or not.
43 * Indicates whether signing out is allowed or whether a complete profile
44 * wipe is required to remove the current enterprise account.
48 signoutAllowed_: true,
51 * Keeps track of whether |onShowHomeButtonChanged_| has been called. See
52 * |onShowHomeButtonChanged_|.
56 onShowHomeButtonChangedCalled_: false,
59 * Track if page initialization is complete. All C++ UI handlers have the
60 * chance to manipulate page content within their InitializePage methods.
61 * This flag is set to true after all initializers have been called.
65 initializationComplete_: false,
68 * When a section is waiting to change its height, this will be a number.
69 * Otherwise it'll be null.
73 sectionHeightChangeTimeout_: null,
76 initializePage: function() {
77 OptionsPage.prototype.initializePage.call(this);
80 // Ensure that navigation events are unblocked on uber page. A reload of
81 // the settings page while an overlay is open would otherwise leave uber
82 // page in a blocked state, where tab switching is not possible.
83 uber.invokeMethodOnParent('stopInterceptingEvents');
85 window.addEventListener('message', this.handleWindowMessage_.bind(this));
87 $('advanced-settings-expander').onclick = function() {
88 self.toggleSectionWithAnimation_(
89 $('advanced-settings'),
90 $('advanced-settings-container'));
92 // If the link was focused (i.e., it was activated using the keyboard)
93 // and it was used to show the section (rather than hiding it), focus
94 // the first element in the container.
95 if (document.activeElement === $('advanced-settings-expander') &&
96 $('advanced-settings').style.height === '') {
97 var focusElement = $('advanced-settings-container').querySelector(
98 'button, input, list, select, a[href]');
100 focusElement.focus();
104 $('advanced-settings').addEventListener('webkitTransitionEnd',
105 this.updateAdvancedSettingsExpander_.bind(this));
108 UIAccountTweaks.applyGuestModeVisibility(document);
109 if (loadTimeData.getBoolean('secondaryUser'))
110 $('secondary-user-banner').hidden = false;
113 // Sync (Sign in) section.
114 this.updateSyncState_(loadTimeData.getValue('syncData'));
116 $('start-stop-sync').onclick = function(event) {
117 if (self.signedIn_) {
118 if (self.signoutAllowed_)
119 SyncSetupOverlay.showStopSyncingUI();
121 ManageProfileOverlay.showDisconnectManagedProfileDialog();
122 } else if (cr.isChromeOS) {
123 SyncSetupOverlay.showSetupUI();
125 SyncSetupOverlay.startSignIn();
128 $('customize-sync').onclick = function(event) {
129 SyncSetupOverlay.showSetupUI();
132 // Internet connection section (ChromeOS only).
134 options.network.NetworkList.decorate($('network-list'));
135 // Show that the network settings are shared if this is a secondary user
136 // in a multi-profile session.
137 if (loadTimeData.getBoolean('secondaryUser')) {
138 var networkIndicator = document.querySelector(
139 '#network-section-header > .controlled-setting-indicator');
140 networkIndicator.setAttribute('controlled-by', 'shared');
141 networkIndicator.location = cr.ui.ArrowLocation.TOP_START;
143 options.network.NetworkList.refreshNetworkData(
144 loadTimeData.getValue('networkData'));
147 // On Startup section.
148 Preferences.getInstance().addEventListener('session.restore_on_startup',
149 this.onRestoreOnStartupChanged_.bind(this));
150 Preferences.getInstance().addEventListener(
151 'session.startup_urls',
153 $('startup-set-pages').disabled = event.value.disabled;
156 $('startup-set-pages').onclick = function() {
157 OptionsPage.navigateToPage('startup');
160 // Appearance section.
161 Preferences.getInstance().addEventListener('browser.show_home_button',
162 this.onShowHomeButtonChanged_.bind(this));
164 Preferences.getInstance().addEventListener('homepage',
165 this.onHomePageChanged_.bind(this));
166 Preferences.getInstance().addEventListener('homepage_is_newtabpage',
167 this.onHomePageIsNtpChanged_.bind(this));
169 $('change-home-page').onclick = function(event) {
170 OptionsPage.navigateToPage('homePageOverlay');
173 chrome.send('requestHotwordAvailable');
175 if ($('set-wallpaper')) {
176 $('set-wallpaper').onclick = function(event) {
177 chrome.send('openWallpaperManager');
181 $('themes-gallery').onclick = function(event) {
182 window.open(loadTimeData.getString('themesGalleryURL'));
184 $('themes-reset').onclick = function(event) {
185 chrome.send('themesReset');
188 if (loadTimeData.getBoolean('profileIsManaged')) {
189 if ($('themes-native-button')) {
190 $('themes-native-button').disabled = true;
191 $('themes-native-button').hidden = true;
193 // Supervised users have just one default theme, even on Linux. So use
194 // the same button for Linux as for the other platforms.
195 $('themes-reset').textContent = loadTimeData.getString('themesReset');
198 // Device section (ChromeOS only).
200 $('keyboard-settings-button').onclick = function(evt) {
201 OptionsPage.navigateToPage('keyboard-overlay');
203 $('pointer-settings-button').onclick = function(evt) {
204 OptionsPage.navigateToPage('pointer-overlay');
209 $('manage-default-search-engines').onclick = function(event) {
210 OptionsPage.navigateToPage('searchEngines');
211 chrome.send('coreOptionsUserMetricsAction',
212 ['Options_ManageSearchEngines']);
214 $('default-search-engine').addEventListener('change',
215 this.setDefaultSearchEngine_);
216 // Without this, the bubble would overlap the uber frame navigation pane
217 // and would not get mouse event as explained in crbug.com/311421.
218 document.querySelector(
219 '#default-search-engine + .controlled-setting-indicator').location =
220 cr.ui.ArrowLocation.TOP_START;
223 if (loadTimeData.valueExists('profilesInfo')) {
224 $('profiles-section').hidden = false;
225 this.maybeShowUserSection_();
227 var profilesList = $('profiles-list');
228 options.browser_options.ProfileList.decorate(profilesList);
229 profilesList.autoExpands = true;
231 // The profiles info data in |loadTimeData| might be stale.
232 this.setProfilesInfo_(loadTimeData.getValue('profilesInfo'));
233 chrome.send('requestProfilesInfo');
235 profilesList.addEventListener('change',
236 this.setProfileViewButtonsStatus_);
237 $('profiles-create').onclick = function(event) {
238 ManageProfileOverlay.showCreateDialog();
240 if (OptionsPage.isSettingsApp()) {
241 $('profiles-app-list-switch').onclick = function(event) {
242 var selectedProfile = self.getSelectedProfileItem_();
243 chrome.send('switchAppListProfile', [selectedProfile.filePath]);
246 $('profiles-manage').onclick = function(event) {
247 ManageProfileOverlay.showManageDialog();
249 $('profiles-delete').onclick = function(event) {
250 var selectedProfile = self.getSelectedProfileItem_();
252 ManageProfileOverlay.showDeleteDialog(selectedProfile);
254 if (loadTimeData.getBoolean('profileIsManaged')) {
255 $('profiles-create').disabled = true;
256 $('profiles-delete').disabled = true;
257 $('profiles-list').canDeleteItems = false;
262 // Username (canonical email) of the currently logged in user or
263 // |kGuestUser| if a guest session is active.
264 this.username_ = loadTimeData.getString('username');
266 this.updateAccountPicture_();
268 $('account-picture').onclick = this.showImagerPickerOverlay_;
269 $('change-picture-caption').onclick = this.showImagerPickerOverlay_;
271 $('manage-accounts-button').onclick = function(event) {
272 OptionsPage.navigateToPage('accounts');
273 chrome.send('coreOptionsUserMetricsAction',
274 ['Options_ManageAccounts']);
277 document.querySelector(
278 '#enable-screen-lock + span > .controlled-setting-indicator').
279 setAttribute('textshared',
280 loadTimeData.getString('screenLockShared'));
282 $('import-data').onclick = function(event) {
283 ImportDataOverlay.show();
284 chrome.send('coreOptionsUserMetricsAction', ['Import_ShowDlg']);
287 if ($('themes-native-button')) {
288 $('themes-native-button').onclick = function(event) {
289 chrome.send('themesSetNative');
294 // Default browser section.
295 if (!cr.isChromeOS) {
296 if (!loadTimeData.getBoolean('showSetDefault')) {
297 $('set-default-browser-section').hidden = true;
299 $('set-as-default-browser').onclick = function(event) {
300 chrome.send('becomeDefaultBrowser');
303 $('auto-launch').onclick = this.handleAutoLaunchChanged_;
307 $('privacyContentSettingsButton').onclick = function(event) {
308 OptionsPage.navigateToPage('content');
309 OptionsPage.showTab($('cookies-nav-tab'));
310 chrome.send('coreOptionsUserMetricsAction',
311 ['Options_ContentSettings']);
313 $('privacyClearDataButton').onclick = function(event) {
314 OptionsPage.navigateToPage('clearBrowserData');
315 chrome.send('coreOptionsUserMetricsAction', ['Options_ClearData']);
317 $('privacyClearDataButton').hidden = OptionsPage.isSettingsApp();
318 // 'metricsReportingEnabled' element is only present on Chrome branded
319 // builds, and the 'metricsReportingCheckboxAction' message is only
320 // handled on ChromeOS.
321 if ($('metricsReportingEnabled') && cr.isChromeOS) {
322 $('metricsReportingEnabled').onclick = function(event) {
323 chrome.send('metricsReportingCheckboxAction',
324 [String(event.currentTarget.checked)]);
328 // Bluetooth (CrOS only).
330 options.system.bluetooth.BluetoothDeviceList.decorate(
331 $('bluetooth-paired-devices-list'));
333 $('bluetooth-add-device').onclick =
334 this.handleAddBluetoothDevice_.bind(this);
336 $('enable-bluetooth').onchange = function(event) {
337 var state = $('enable-bluetooth').checked;
338 chrome.send('bluetoothEnableChange', [Boolean(state)]);
341 $('bluetooth-reconnect-device').onclick = function(event) {
342 var device = $('bluetooth-paired-devices-list').selectedItem;
343 var address = device.address;
344 chrome.send('updateBluetoothDevice', [address, 'connect']);
345 OptionsPage.closeOverlay();
348 $('bluetooth-paired-devices-list').addEventListener('change',
350 var item = $('bluetooth-paired-devices-list').selectedItem;
351 var disabled = !item || item.connected || !item.connectable;
352 $('bluetooth-reconnect-device').disabled = disabled;
356 // Passwords and Forms section.
357 $('autofill-settings').onclick = function(event) {
358 OptionsPage.navigateToPage('autofill');
359 chrome.send('coreOptionsUserMetricsAction',
360 ['Options_ShowAutofillSettings']);
362 $('manage-passwords').onclick = function(event) {
363 OptionsPage.navigateToPage('passwords');
364 OptionsPage.showTab($('passwords-nav-tab'));
365 chrome.send('coreOptionsUserMetricsAction',
366 ['Options_ShowPasswordManager']);
368 if (cr.isChromeOS && UIAccountTweaks.loggedInAsGuest()) {
369 // Disable and turn off Autofill in guest mode.
370 var autofillEnabled = $('autofill-enabled');
371 autofillEnabled.disabled = true;
372 autofillEnabled.checked = false;
373 cr.dispatchSimpleEvent(autofillEnabled, 'change');
374 $('autofill-settings').disabled = true;
376 // Disable and turn off Password Manager in guest mode.
377 var passwordManagerEnabled = $('password-manager-enabled');
378 passwordManagerEnabled.disabled = true;
379 passwordManagerEnabled.checked = false;
380 cr.dispatchSimpleEvent(passwordManagerEnabled, 'change');
381 $('manage-passwords').disabled = true;
385 $('mac-passwords-warning').hidden =
386 !loadTimeData.getBoolean('multiple_profiles');
390 if (!cr.isChromeOS) {
391 $('proxiesConfigureButton').onclick = function(event) {
392 chrome.send('showNetworkProxySettings');
396 // Easy Unlock section.
397 if (loadTimeData.getBoolean('easyUnlockEnabled')) {
398 $('easy-unlock-section').hidden = false;
399 $('easy-unlock-setup-button').onclick = function(event) {
400 chrome.send('launchEasyUnlockSetup');
404 // Web Content section.
405 $('fontSettingsCustomizeFontsButton').onclick = function(event) {
406 OptionsPage.navigateToPage('fonts');
407 chrome.send('coreOptionsUserMetricsAction', ['Options_FontSettings']);
409 $('defaultFontSize').onchange = function(event) {
410 var value = event.target.options[event.target.selectedIndex].value;
411 Preferences.setIntegerPref(
412 'webkit.webprefs.default_fixed_font_size',
413 value - OptionsPage.SIZE_DIFFERENCE_FIXED_STANDARD, true);
414 chrome.send('defaultFontSizeAction', [String(value)]);
416 $('defaultZoomFactor').onchange = function(event) {
417 chrome.send('defaultZoomFactorAction',
418 [String(event.target.options[event.target.selectedIndex].value)]);
421 // Languages section.
422 var showLanguageOptions = function(event) {
423 OptionsPage.navigateToPage('languages');
424 chrome.send('coreOptionsUserMetricsAction',
425 ['Options_LanuageAndSpellCheckSettings']);
427 $('language-button').onclick = showLanguageOptions;
428 $('manage-languages').onclick = showLanguageOptions;
430 // Downloads section.
431 Preferences.getInstance().addEventListener('download.default_directory',
432 this.onDefaultDownloadDirectoryChanged_.bind(this));
433 $('downloadLocationChangeButton').onclick = function(event) {
434 chrome.send('selectDownloadLocation');
436 if (!cr.isChromeOS) {
437 $('autoOpenFileTypesResetToDefault').onclick = function(event) {
438 chrome.send('autoOpenFileTypesAction');
441 $('disable-drive-row').hidden =
442 UIAccountTweaks.loggedInAsLocallyManagedUser();
445 // HTTPS/SSL section.
446 if (cr.isWindows || cr.isMac) {
447 $('certificatesManageButton').onclick = function(event) {
448 chrome.send('showManageSSLCertificates');
451 $('certificatesManageButton').onclick = function(event) {
452 OptionsPage.navigateToPage('certificates');
453 chrome.send('coreOptionsUserMetricsAction',
454 ['Options_ManageSSLCertificates']);
458 // Cloud Print section.
459 // 'cloudPrintProxyEnabled' is true for Chrome branded builds on
460 // certain platforms, or could be enabled by a lab.
461 if (!cr.isChromeOS) {
462 $('cloudPrintConnectorSetupButton').onclick = function(event) {
463 if ($('cloudPrintManageButton').style.display == 'none') {
464 // Disable the button, set its text to the intermediate state.
465 $('cloudPrintConnectorSetupButton').textContent =
466 loadTimeData.getString('cloudPrintConnectorEnablingButton');
467 $('cloudPrintConnectorSetupButton').disabled = true;
468 chrome.send('showCloudPrintSetupDialog');
470 chrome.send('disableCloudPrintConnector');
474 $('cloudPrintManageButton').onclick = function(event) {
475 chrome.send('showCloudPrintManagePage');
478 if (loadTimeData.getBoolean('cloudPrintShowMDnsOptions')) {
479 $('cloudprint-options-mdns').hidden = false;
480 $('cloudprint-options-nomdns').hidden = true;
481 $('cloudPrintDevicesPageButton').onclick = function() {
482 chrome.send('showCloudPrintDevicesPage');
486 // Accessibility section (CrOS only).
488 var updateAccessibilitySettingsButton = function() {
489 $('accessibility-settings').hidden =
490 !($('accessibility-spoken-feedback-check').checked);
492 Preferences.getInstance().addEventListener(
493 'settings.accessibility',
494 updateAccessibilitySettingsButton);
495 $('accessibility-settings-button').onclick = function(event) {
496 window.open(loadTimeData.getString('accessibilitySettingsURL'));
498 $('accessibility-spoken-feedback-check').onchange = function(event) {
499 chrome.send('spokenFeedbackChange',
500 [$('accessibility-spoken-feedback-check').checked]);
501 updateAccessibilitySettingsButton();
503 updateAccessibilitySettingsButton();
505 $('accessibility-high-contrast-check').onchange = function(event) {
506 chrome.send('highContrastChange',
507 [$('accessibility-high-contrast-check').checked]);
510 var updateDelayDropdown = function() {
511 $('accessibility-autoclick-dropdown').disabled =
512 !$('accessibility-autoclick-check').checked;
514 Preferences.getInstance().addEventListener(
515 $('accessibility-autoclick-check').getAttribute('pref'),
516 updateDelayDropdown);
519 // Display management section (CrOS only).
521 $('display-options').onclick = function(event) {
522 OptionsPage.navigateToPage('display');
523 chrome.send('coreOptionsUserMetricsAction',
524 ['Options_Display']);
528 // Factory reset section (CrOS only).
530 $('factory-reset-restart').onclick = function(event) {
531 OptionsPage.navigateToPage('factoryResetData');
532 chrome.send('onPowerwashDialogShow');
537 if (!cr.isChromeOS) {
538 var updateGpuRestartButton = function() {
539 $('gpu-mode-reset-restart').hidden =
540 loadTimeData.getBoolean('gpuEnabledAtStart') ==
541 $('gpu-mode-checkbox').checked;
543 Preferences.getInstance().addEventListener(
544 $('gpu-mode-checkbox').getAttribute('pref'),
545 updateGpuRestartButton);
546 $('gpu-mode-reset-restart-button').onclick = function(event) {
547 chrome.send('restartBrowser');
549 updateGpuRestartButton();
552 // Reset profile settings section.
553 $('reset-profile-settings').onclick = function(event) {
554 OptionsPage.navigateToPage('resetProfileSettings');
556 $('reset-profile-settings-section').hidden =
557 !loadTimeData.getBoolean('enableResetProfileSettings');
561 didShowPage: function() {
562 $('search-field').focus();
566 * Called after all C++ UI handlers have called InitializePage to notify
567 * that initialization is complete.
570 notifyInitializationComplete_: function() {
571 this.initializationComplete_ = true;
572 cr.dispatchSimpleEvent(document, 'initializationComplete');
576 * Event listener for the 'session.restore_on_startup' pref.
577 * @param {Event} event The preference change event.
580 onRestoreOnStartupChanged_: function(event) {
581 /** @const */ var showHomePageValue = 0;
583 if (event.value.value == showHomePageValue) {
584 // If the user previously selected "Show the homepage", the
585 // preference will already be migrated to "Open a specific page". So
586 // the only way to reach this code is if the 'restore on startup'
587 // preference is managed.
588 assert(event.value.controlledBy);
590 // Select "open the following pages" and lock down the list of URLs
591 // to reflect the intention of the policy.
592 $('startup-show-pages').checked = true;
593 StartupOverlay.getInstance().setControlsDisabled(true);
595 // Re-enable the controls in the startup overlay if necessary.
596 StartupOverlay.getInstance().updateControlStates();
601 * Handler for messages sent from the main uber page.
602 * @param {Event} e The 'message' event from the uber page.
605 handleWindowMessage_: function(e) {
606 if (e.data.method == 'frameSelected')
607 $('search-field').focus();
611 * Animatedly changes height |from| a px number |to| a px number.
612 * @param {HTMLElement} section The section to animate.
613 * @param {HTMLElement} container The container of |section|.
614 * @param {boolean} showing Whether to go from 0 -> container height or
615 * container height -> 0.
618 animatedSectionHeightChange_: function(section, container, showing) {
619 // If the section is already animating, dispatch a synthetic transition
620 // end event as the upcoming code will cancel the current one.
621 if (section.classList.contains('sliding'))
622 cr.dispatchSimpleEvent(section, 'webkitTransitionEnd');
624 this.addTransitionEndListener_(section);
626 section.hidden = false;
627 section.style.height = (showing ? 0 : container.offsetHeight) + 'px';
628 section.classList.add('sliding');
630 if (this.sectionHeightChangeTimeout_ !== null)
631 clearTimeout(this.sectionHeightChangeTimeout_);
633 this.sectionHeightChangeTimeout_ = setTimeout(function() {
634 section.style.height = (showing ? container.offsetHeight : 0) + 'px';
635 this.sectionHeightChangeTimeout_ = null;
640 * Shows the given section.
641 * @param {HTMLElement} section The section to be shown.
642 * @param {HTMLElement} container The container for the section. Must be
643 * inside of |section|.
644 * @param {boolean} animate Indicate if the expansion should be animated.
647 showSection_: function(section, container, animate) {
648 // Delay starting the transition if animating so that hidden change will
651 this.animatedSectionHeightChange_(section, container, true);
653 section.hidden = false;
654 section.style.height = 'auto';
659 * Shows the given section, with animation.
660 * @param {HTMLElement} section The section to be shown.
661 * @param {HTMLElement} container The container for the section. Must be
662 * inside of |section|.
665 showSectionWithAnimation_: function(section, container) {
666 this.showSection_(section, container, /* animate */ true);
670 * Hides the given |section| with animation.
671 * @param {HTMLElement} section The section to be hidden.
672 * @param {HTMLElement} container The container for the section. Must be
673 * inside of |section|.
676 hideSectionWithAnimation_: function(section, container) {
677 this.animatedSectionHeightChange_(section, container, false);
681 * Toggles the visibility of |section| in an animated way.
682 * @param {HTMLElement} section The section to be toggled.
683 * @param {HTMLElement} container The container for the section. Must be
684 * inside of |section|.
687 toggleSectionWithAnimation_: function(section, container) {
688 if (BrowserOptions.shouldShowSection_(section))
689 this.showSectionWithAnimation_(section, container);
691 this.hideSectionWithAnimation_(section, container);
695 * Scrolls the settings page to make the section visible auto-expanding
696 * advanced settings if required. The transition is not animated. This
697 * method is used to ensure that a section associated with an overlay
698 * is visible when the overlay is closed.
699 * @param {!Element} section The section to make visible.
702 scrollToSection_: function(section) {
703 var advancedSettings = $('advanced-settings');
704 var container = $('advanced-settings-container');
705 if (advancedSettings.hidden && section.parentNode == container) {
706 this.showSection_($('advanced-settings'),
707 $('advanced-settings-container'),
708 /* animate */ false);
709 this.updateAdvancedSettingsExpander_();
712 if (!this.initializationComplete_) {
714 var callback = function() {
715 document.removeEventListener('initializationComplete', callback);
716 self.scrollToSection_(section);
718 document.addEventListener('initializationComplete', callback);
722 var pageContainer = $('page-container');
723 // pageContainer.offsetTop is relative to the screen.
724 var pageTop = pageContainer.offsetTop;
725 var sectionBottom = section.offsetTop + section.offsetHeight;
726 // section.offsetTop is relative to the 'page-container'.
727 var sectionTop = section.offsetTop;
728 if (pageTop + sectionBottom > document.body.scrollHeight ||
729 pageTop + sectionTop < 0) {
730 // Currently not all layout updates are guaranteed to precede the
731 // initializationComplete event (for example 'set-as-default-browser'
732 // button) leaving some uncertainty in the optimal scroll position.
733 // The section is placed approximately in the middle of the screen.
734 var top = Math.min(0, document.body.scrollHeight / 2 - sectionBottom);
735 pageContainer.style.top = top + 'px';
736 pageContainer.oldScrollTop = -top;
741 * Adds a |webkitTransitionEnd| listener to the given section so that
742 * it can be animated. The listener will only be added to a given section
743 * once, so this can be called as multiple times.
744 * @param {HTMLElement} section The section to be animated.
747 addTransitionEndListener_: function(section) {
748 if (section.hasTransitionEndListener_)
751 section.addEventListener('webkitTransitionEnd',
752 this.onTransitionEnd_.bind(this));
753 section.hasTransitionEndListener_ = true;
757 * Called after an animation transition has ended.
758 * @param {Event} The webkitTransitionEnd event. NOTE: May be synthetic.
761 onTransitionEnd_: function(event) {
762 if (event.propertyName && event.propertyName != 'height') {
763 // If not a synthetic event or a real transition we care about, bail.
767 var section = event.target;
768 section.classList.remove('sliding');
770 if (!event.propertyName) {
771 // Only real transitions past this point.
775 if (section.style.height == '0px') {
776 // Hide the content so it can't get tab focus.
777 section.hidden = true;
778 section.style.height = '';
780 // Set the section height to 'auto' to allow for size changes
781 // (due to font change or dynamic content).
782 section.style.height = 'auto';
787 updateAdvancedSettingsExpander_: function() {
788 var expander = $('advanced-settings-expander');
789 if (BrowserOptions.shouldShowSection_($('advanced-settings')))
790 expander.textContent = loadTimeData.getString('showAdvancedSettings');
792 expander.textContent = loadTimeData.getString('hideAdvancedSettings');
796 * Updates the sync section with the given state.
797 * @param {Object} syncData A bunch of data records that describe the status
798 * of the sync system.
801 updateSyncState_: function(syncData) {
802 if (!syncData.signinAllowed &&
803 (!syncData.supervisedUser || !cr.isChromeOS)) {
804 $('sync-section').hidden = true;
805 this.maybeShowUserSection_();
809 $('sync-section').hidden = false;
810 this.maybeShowUserSection_();
812 var subSection = $('sync-section').firstChild;
814 if (subSection.nodeType == Node.ELEMENT_NODE)
815 subSection.hidden = syncData.supervisedUser;
816 subSection = subSection.nextSibling;
819 if (syncData.supervisedUser) {
820 $('account-picture-wrapper').hidden = false;
821 $('sync-general').hidden = false;
822 $('sync-status').hidden = true;
826 // If the user gets signed out while the advanced sync settings dialog is
827 // visible, say, due to a dashboard clear, close the dialog.
828 // However, if the user gets signed out as a result of abandoning first
829 // time sync setup, do not call closeOverlay as it will redirect the
830 // browser to the main settings page and override any in-progress
831 // user-initiated navigation. See crbug.com/278030.
832 // Note: SyncSetupOverlay.closeOverlay is a no-op if the overlay is
834 if (this.signedIn_ && !syncData.signedIn && !syncData.setupInProgress)
835 SyncSetupOverlay.closeOverlay();
837 this.signedIn_ = syncData.signedIn;
839 // Display the "advanced settings" button if we're signed in and sync is
840 // not managed/disabled. If the user is signed in, but sync is disabled,
841 // this button is used to re-enable sync.
842 var customizeSyncButton = $('customize-sync');
843 customizeSyncButton.hidden = !this.signedIn_ ||
845 !syncData.syncSystemEnabled;
847 // Only modify the customize button's text if the new text is different.
848 // Otherwise, it can affect search-highlighting in the settings page.
849 // See http://crbug.com/268265.
850 var customizeSyncButtonNewText = syncData.setupCompleted ?
851 loadTimeData.getString('customizeSync') :
852 loadTimeData.getString('syncButtonTextStart');
853 if (customizeSyncButton.textContent != customizeSyncButtonNewText)
854 customizeSyncButton.textContent = customizeSyncButtonNewText;
856 // Disable the "sign in" button if we're currently signing in, or if we're
857 // already signed in and signout is not allowed.
858 var signInButton = $('start-stop-sync');
859 signInButton.disabled = syncData.setupInProgress ||
860 !syncData.signoutAllowed;
861 this.signoutAllowed_ = syncData.signoutAllowed;
862 if (!syncData.signoutAllowed)
863 $('start-stop-sync-indicator').setAttribute('controlled-by', 'policy');
865 $('start-stop-sync-indicator').removeAttribute('controlled-by');
867 // Hide the "sign in" button on Chrome OS, and show it on desktop Chrome.
868 signInButton.hidden = cr.isChromeOS;
870 signInButton.textContent =
872 loadTimeData.getString('syncButtonTextStop') :
873 syncData.setupInProgress ?
874 loadTimeData.getString('syncButtonTextInProgress') :
875 loadTimeData.getString('syncButtonTextSignIn');
876 $('start-stop-sync-indicator').hidden = signInButton.hidden;
878 // TODO(estade): can this just be textContent?
879 $('sync-status-text').innerHTML = syncData.statusText;
880 var statusSet = syncData.statusText.length != 0;
881 $('sync-overview').hidden = statusSet;
882 $('sync-status').hidden = !statusSet;
884 $('sync-action-link').textContent = syncData.actionLinkText;
885 // Don't show the action link if it is empty or undefined.
886 $('sync-action-link').hidden = syncData.actionLinkText.length == 0;
887 $('sync-action-link').disabled = syncData.managed ||
888 !syncData.syncSystemEnabled;
890 // On Chrome OS, sign out the user and sign in again to get fresh
891 // credentials on auth errors.
892 $('sync-action-link').onclick = function(event) {
893 if (cr.isChromeOS && syncData.hasError)
894 SyncSetupOverlay.doSignOutOnAuthError();
896 SyncSetupOverlay.showSetupUI();
899 if (syncData.hasError)
900 $('sync-status').classList.add('sync-error');
902 $('sync-status').classList.remove('sync-error');
904 // Disable the "customize / set up sync" button if sync has an
905 // unrecoverable error. Also disable the button if sync has not been set
906 // up and the user is being presented with a link to re-auth.
907 // See crbug.com/289791.
908 customizeSyncButton.disabled =
909 syncData.hasUnrecoverableError ||
910 (!syncData.setupCompleted && !$('sync-action-link').hidden);
912 // Move #enable-auto-login-checkbox to a different location on CrOS.
914 $('sync-general').insertBefore($('sync-status').nextSibling,
915 $('enable-auto-login-checkbox'));
917 $('enable-auto-login-checkbox').hidden = !syncData.autoLoginVisible;
921 * Update the UI depending on whether the current profile has a pairing for
923 * @param {boolean} hasPairing True if the current profile has a pairing.
925 updateEasyUnlock_: function(hasPairing) {
926 $('easy-unlock-setup').hidden = hasPairing;
927 $('easy-unlock-enable').hidden = !hasPairing;
931 * Update the UI depending on whether the current profile manages any
933 * @param {boolean} show True if the current profile manages any supervised
936 updateManagesSupervisedUsers_: function(show) {
937 $('profiles-supervised-dashboard-tip').hidden = !show;
938 this.maybeShowUserSection_();
942 * Get the start/stop sync button DOM element. Used for testing.
943 * @return {DOMElement} The start/stop sync button.
946 getStartStopSyncButton_: function() {
947 return $('start-stop-sync');
951 * Event listener for the 'show home button' preference. Shows/hides the
952 * UI for changing the home page with animation, unless this is the first
953 * time this function is called, in which case there is no animation.
954 * @param {Event} event The preference change event.
956 onShowHomeButtonChanged_: function(event) {
957 var section = $('change-home-page-section');
958 if (this.onShowHomeButtonChangedCalled_) {
959 var container = $('change-home-page-section-container');
960 if (event.value.value)
961 this.showSectionWithAnimation_(section, container);
963 this.hideSectionWithAnimation_(section, container);
965 section.hidden = !event.value.value;
966 this.onShowHomeButtonChangedCalled_ = true;
971 * Activates the Hotword section from the System settings page.
974 showHotwordSection_: function(opt_error) {
975 $('hotword-search').hidden = false;
979 * Event listener for the 'homepage is NTP' preference. Updates the label
980 * next to the 'Change' button.
981 * @param {Event} event The preference change event.
983 onHomePageIsNtpChanged_: function(event) {
984 if (!event.value.uncommitted) {
985 $('home-page-url').hidden = event.value.value;
986 $('home-page-ntp').hidden = !event.value.value;
991 * Event listener for changes to the homepage preference. Updates the label
992 * next to the 'Change' button.
993 * @param {Event} event The preference change event.
995 onHomePageChanged_: function(event) {
996 if (!event.value.uncommitted)
997 $('home-page-url').textContent = this.stripHttp_(event.value.value);
1001 * Removes the 'http://' from a URL, like the omnibox does. If the string
1002 * doesn't start with 'http://' it is returned unchanged.
1003 * @param {string} url The url to be processed
1004 * @return {string} The url with the 'http://' removed.
1006 stripHttp_: function(url) {
1007 return url.replace(/^http:\/\//, '');
1011 * Shows the autoLaunch preference and initializes its checkbox value.
1012 * @param {bool} enabled Whether autolaunch is enabled or or not.
1015 updateAutoLaunchState_: function(enabled) {
1016 $('auto-launch-option').hidden = false;
1017 $('auto-launch').checked = enabled;
1021 * Called when the value of the download.default_directory preference
1023 * @param {Event} event Change event.
1026 onDefaultDownloadDirectoryChanged_: function(event) {
1027 $('downloadLocationPath').value = event.value.value;
1028 if (cr.isChromeOS) {
1029 // On ChromeOS, replace /special/drive-<hash>/root with "Google Drive"
1030 // for remote files, /home/chronos/user/Downloads or
1031 // /home/chronos/u-<hash>/Downloads with "Downloads" for local paths,
1032 // and '/' with ' \u203a ' (angled quote sign) everywhere. The modified
1033 // path is used only for display purpose.
1034 var path = $('downloadLocationPath').value;
1035 path = path.replace(/^\/special\/drive[^\/]*\/root/, 'Google Drive');
1036 path = path.replace(/^\/home\/chronos\/(user|u-[^\/]*)\//, '');
1037 path = path.replace(/\//g, ' \u203a ');
1038 $('downloadLocationPath').value = path;
1040 $('download-location-label').classList.toggle('disabled',
1041 event.value.disabled);
1042 $('downloadLocationChangeButton').disabled = event.value.disabled;
1046 * Update the Default Browsers section based on the current state.
1047 * @param {string} statusString Description of the current default state.
1048 * @param {boolean} isDefault Whether or not the browser is currently
1050 * @param {boolean} canBeDefault Whether or not the browser can be default.
1053 updateDefaultBrowserState_: function(statusString, isDefault,
1055 if (!cr.isChromeOS) {
1056 var label = $('default-browser-state');
1057 label.textContent = statusString;
1059 $('set-as-default-browser').hidden = !canBeDefault || isDefault;
1064 * Clears the search engine popup.
1067 clearSearchEngines_: function() {
1068 $('default-search-engine').textContent = '';
1072 * Updates the search engine popup with the given entries.
1073 * @param {Array} engines List of available search engines.
1074 * @param {number} defaultValue The value of the current default engine.
1075 * @param {boolean} defaultManaged Whether the default search provider is
1076 * managed. If true, the default search provider can't be changed.
1079 updateSearchEngines_: function(engines, defaultValue, defaultManaged) {
1080 this.clearSearchEngines_();
1081 engineSelect = $('default-search-engine');
1082 engineSelect.disabled = defaultManaged;
1083 if (defaultManaged && defaultValue == -1)
1085 engineCount = engines.length;
1086 var defaultIndex = -1;
1087 for (var i = 0; i < engineCount; i++) {
1088 var engine = engines[i];
1089 var option = new Option(engine.name, engine.index);
1090 if (defaultValue == option.value)
1092 engineSelect.appendChild(option);
1094 if (defaultIndex >= 0)
1095 engineSelect.selectedIndex = defaultIndex;
1099 * Set the default search engine based on the popup selection.
1102 setDefaultSearchEngine_: function() {
1103 var engineSelect = $('default-search-engine');
1104 var selectedIndex = engineSelect.selectedIndex;
1105 if (selectedIndex >= 0) {
1106 var selection = engineSelect.options[selectedIndex];
1107 chrome.send('setDefaultSearchEngine', [String(selection.value)]);
1112 * Sets or clear whether Chrome should Auto-launch on computer startup.
1115 handleAutoLaunchChanged_: function() {
1116 chrome.send('toggleAutoLaunch', [$('auto-launch').checked]);
1120 * Get the selected profile item from the profile list. This also works
1121 * correctly if the list is not displayed.
1122 * @return {Object} the profile item object, or null if nothing is selected.
1125 getSelectedProfileItem_: function() {
1126 var profilesList = $('profiles-list');
1127 if (profilesList.hidden) {
1128 if (profilesList.dataModel.length > 0)
1129 return profilesList.dataModel.item(0);
1131 return profilesList.selectedItem;
1137 * Helper function to set the status of profile view buttons to disabled or
1138 * enabled, depending on the number of profiles and selection status of the
1142 setProfileViewButtonsStatus_: function() {
1143 var profilesList = $('profiles-list');
1144 var selectedProfile = profilesList.selectedItem;
1145 var hasSelection = selectedProfile != null;
1146 var hasSingleProfile = profilesList.dataModel.length == 1;
1147 var isManaged = loadTimeData.getBoolean('profileIsManaged');
1148 $('profiles-manage').disabled = !hasSelection ||
1149 !selectedProfile.isCurrentProfile;
1150 if (hasSelection && !selectedProfile.isCurrentProfile)
1151 $('profiles-manage').title = loadTimeData.getString('currentUserOnly');
1153 $('profiles-manage').title = '';
1154 $('profiles-delete').disabled = isManaged ||
1155 (!hasSelection && !hasSingleProfile);
1156 if (OptionsPage.isSettingsApp()) {
1157 $('profiles-app-list-switch').disabled = !hasSelection ||
1158 selectedProfile.isCurrentProfile;
1160 var importData = $('import-data');
1162 importData.disabled = $('import-data').disabled = hasSelection &&
1163 !selectedProfile.isCurrentProfile;
1168 * Display the correct dialog layout, depending on how many profiles are
1170 * @param {number} numProfiles The number of profiles to display.
1173 setProfileViewSingle_: function(numProfiles) {
1174 var hasSingleProfile = numProfiles == 1;
1175 $('profiles-list').hidden = hasSingleProfile;
1176 $('profiles-single-message').hidden = !hasSingleProfile;
1177 $('profiles-manage').hidden =
1178 hasSingleProfile || OptionsPage.isSettingsApp();
1179 $('profiles-delete').textContent = hasSingleProfile ?
1180 loadTimeData.getString('profilesDeleteSingle') :
1181 loadTimeData.getString('profilesDelete');
1182 if (OptionsPage.isSettingsApp())
1183 $('profiles-app-list-switch').hidden = hasSingleProfile;
1187 * Adds all |profiles| to the list.
1188 * @param {Array.<Object>} profiles An array of profile info objects.
1189 * each object is of the form:
1191 * name: "Profile Name",
1192 * iconURL: "chrome://path/to/icon/image",
1193 * filePath: "/path/to/profile/data/on/disk",
1194 * isCurrentProfile: false
1198 setProfilesInfo_: function(profiles) {
1199 this.setProfileViewSingle_(profiles.length);
1200 // add it to the list, even if the list is hidden so we can access it
1202 $('profiles-list').dataModel = new ArrayDataModel(profiles);
1204 // Received new data. If showing the "manage" overlay, keep it up to
1205 // date. If showing the "delete" overlay, close it.
1206 if (ManageProfileOverlay.getInstance().visible &&
1207 !$('manage-profile-overlay-manage').hidden) {
1208 ManageProfileOverlay.showManageDialog();
1210 ManageProfileOverlay.getInstance().visible = false;
1213 this.setProfileViewButtonsStatus_();
1217 * Reports managed user import errors to the ManagedUserImportOverlay.
1218 * @param {string} error The error message to display.
1221 showManagedUserImportError_: function(error) {
1222 ManagedUserImportOverlay.onError(error);
1226 * Reports successful importing of a managed user to
1227 * the ManagedUserImportOverlay.
1230 showManagedUserImportSuccess_: function() {
1231 ManagedUserImportOverlay.onSuccess();
1235 * Reports an error to the "create" overlay during profile creation.
1236 * @param {string} error The error message to display.
1239 showCreateProfileError_: function(error) {
1240 CreateProfileOverlay.onError(error);
1244 * Sends a warning message to the "create" overlay during profile creation.
1245 * @param {string} warning The warning message to display.
1248 showCreateProfileWarning_: function(warning) {
1249 CreateProfileOverlay.onWarning(warning);
1253 * Reports successful profile creation to the "create" overlay.
1254 * @param {Object} profileInfo An object of the form:
1256 * name: "Profile Name",
1257 * filePath: "/path/to/profile/data/on/disk"
1258 * isManaged: (true|false),
1262 showCreateProfileSuccess_: function(profileInfo) {
1263 CreateProfileOverlay.onSuccess(profileInfo);
1267 * Returns the currently active profile for this browser window.
1268 * @return {Object} A profile info object.
1271 getCurrentProfile_: function() {
1272 for (var i = 0; i < $('profiles-list').dataModel.length; i++) {
1273 var profile = $('profiles-list').dataModel.item(i);
1274 if (profile.isCurrentProfile)
1279 'There should always be a current profile, but none found.');
1282 setNativeThemeButtonEnabled_: function(enabled) {
1283 var button = $('themes-native-button');
1285 button.disabled = !enabled;
1288 setThemesResetButtonEnabled_: function(enabled) {
1289 $('themes-reset').disabled = !enabled;
1292 setAccountPictureManaged_: function(managed) {
1293 var picture = $('account-picture');
1294 if (managed || UIAccountTweaks.loggedInAsGuest()) {
1295 picture.disabled = true;
1296 ChangePictureOptions.closeOverlay();
1298 picture.disabled = false;
1301 // Create a synthetic pref change event decorated as
1302 // CoreOptionsHandler::CreateValueForPref() does.
1303 var event = new Event('account-picture');
1305 event.value = { controlledBy: 'policy' };
1308 $('account-picture-indicator').handlePrefChange(event);
1312 * (Re)loads IMG element with current user account picture.
1315 updateAccountPicture_: function() {
1316 var picture = $('account-picture');
1318 picture.src = 'chrome://userimage/' + this.username_ + '?id=' +
1323 setWallpaperManaged_: function(managed) {
1324 var button = $('set-wallpaper');
1325 button.disabled = !!managed;
1327 // Create a synthetic pref change event decorated as
1328 // CoreOptionsHandler::CreateValueForPref() does.
1329 var event = new Event('account-picture');
1331 event.value = { controlledBy: 'policy' };
1334 $('wallpaper-indicator').handlePrefChange(event);
1338 * Handle the 'add device' button click.
1341 handleAddBluetoothDevice_: function() {
1342 chrome.send('findBluetoothDevices');
1343 OptionsPage.showPageByName('bluetooth', false);
1347 * Enables or disables the Manage SSL Certificates button.
1350 enableCertificateButton_: function(enabled) {
1351 $('certificatesManageButton').disabled = !enabled;
1355 * Enables factory reset section.
1358 enableFactoryResetSection_: function() {
1359 $('factory-reset-section').hidden = false;
1363 * Set the checked state of the metrics reporting checkbox.
1366 setMetricsReportingCheckboxState_: function(checked, disabled) {
1367 $('metricsReportingEnabled').checked = checked;
1368 $('metricsReportingEnabled').disabled = disabled;
1374 setMetricsReportingSettingVisibility_: function(visible) {
1376 $('metricsReportingSetting').style.display = 'block';
1378 $('metricsReportingSetting').style.display = 'none';
1382 * Set the font size selected item. This item actually reflects two
1383 * preferences: the default font size and the default fixed font size.
1385 * @param {Object} pref Information about the font size preferences.
1386 * @param {number} pref.value The value of the default font size pref.
1387 * @param {boolean} pref.disabled True if either pref not user modifiable.
1388 * @param {string} pref.controlledBy The source of the pref value(s) if
1389 * either pref is currently not controlled by the user.
1392 setFontSize_: function(pref) {
1393 var selectCtl = $('defaultFontSize');
1394 selectCtl.disabled = pref.disabled;
1395 // Create a synthetic pref change event decorated as
1396 // CoreOptionsHandler::CreateValueForPref() does.
1397 var event = new Event('synthetic-font-size');
1400 controlledBy: pref.controlledBy,
1401 disabled: pref.disabled
1403 $('font-size-indicator').handlePrefChange(event);
1405 for (var i = 0; i < selectCtl.options.length; i++) {
1406 if (selectCtl.options[i].value == pref.value) {
1407 selectCtl.selectedIndex = i;
1409 selectCtl.remove($('Custom').index);
1414 // Add/Select Custom Option in the font size label list.
1416 var option = new Option(loadTimeData.getString('fontSizeLabelCustom'),
1418 option.setAttribute('id', 'Custom');
1419 selectCtl.add(option);
1421 $('Custom').selected = true;
1425 * Populate the page zoom selector with values received from the caller.
1426 * @param {Array} items An array of items to populate the selector.
1427 * each object is an array with three elements as follows:
1428 * 0: The title of the item (string).
1429 * 1: The value of the item (number).
1430 * 2: Whether the item should be selected (boolean).
1433 setupPageZoomSelector_: function(items) {
1434 var element = $('defaultZoomFactor');
1436 // Remove any existing content.
1437 element.textContent = '';
1439 // Insert new child nodes into select element.
1440 var value, title, selected;
1441 for (var i = 0; i < items.length; i++) {
1442 title = items[i][0];
1443 value = items[i][1];
1444 selected = items[i][2];
1445 element.appendChild(new Option(title, value, false, selected));
1450 * Shows/hides the autoOpenFileTypesResetToDefault button and label, with
1452 * @param {boolean} display Whether to show the button and label or not.
1455 setAutoOpenFileTypesDisplayed_: function(display) {
1459 if ($('advanced-settings').hidden) {
1460 // If the Advanced section is hidden, don't animate the transition.
1461 $('auto-open-file-types-section').hidden = !display;
1464 this.showSectionWithAnimation_(
1465 $('auto-open-file-types-section'),
1466 $('auto-open-file-types-container'));
1468 this.hideSectionWithAnimation_(
1469 $('auto-open-file-types-section'),
1470 $('auto-open-file-types-container'));
1476 * Set the enabled state for the proxy settings button.
1479 setupProxySettingsSection_: function(disabled, extensionControlled) {
1480 if (!cr.isChromeOS) {
1481 $('proxiesConfigureButton').disabled = disabled;
1482 $('proxiesLabel').textContent =
1483 loadTimeData.getString(extensionControlled ?
1484 'proxiesLabelExtension' : 'proxiesLabelSystem');
1489 * Set the Cloud Print proxy UI to enabled, disabled, or processing.
1492 setupCloudPrintConnectorSection_: function(disabled, label, allowed) {
1493 if (!cr.isChromeOS) {
1494 $('cloudPrintConnectorLabel').textContent = label;
1495 if (disabled || !allowed) {
1496 $('cloudPrintConnectorSetupButton').textContent =
1497 loadTimeData.getString('cloudPrintConnectorDisabledButton');
1498 $('cloudPrintManageButton').style.display = 'none';
1500 $('cloudPrintConnectorSetupButton').textContent =
1501 loadTimeData.getString('cloudPrintConnectorEnabledButton');
1502 $('cloudPrintManageButton').style.display = 'inline';
1504 $('cloudPrintConnectorSetupButton').disabled = !allowed;
1511 removeCloudPrintConnectorSection_: function() {
1512 if (!cr.isChromeOS) {
1513 var connectorSectionElm = $('cloud-print-connector-section');
1514 if (connectorSectionElm)
1515 connectorSectionElm.parentNode.removeChild(connectorSectionElm);
1520 * Set the initial state of the spoken feedback checkbox.
1523 setSpokenFeedbackCheckboxState_: function(checked) {
1524 $('accessibility-spoken-feedback-check').checked = checked;
1528 * Set the initial state of the high contrast checkbox.
1531 setHighContrastCheckboxState_: function(checked) {
1532 $('accessibility-high-contrast-check').checked = checked;
1536 * Set the initial state of the virtual keyboard checkbox.
1539 setVirtualKeyboardCheckboxState_: function(checked) {
1540 // TODO(zork): Update UI
1544 * Show/hide mouse settings slider.
1547 showMouseControls_: function(show) {
1548 $('mouse-settings').hidden = !show;
1552 * Show/hide touchpad-related settings.
1555 showTouchpadControls_: function(show) {
1556 $('touchpad-settings').hidden = !show;
1557 $('accessibility-tap-dragging').hidden = !show;
1561 * Activate the Bluetooth settings section on the System settings page.
1564 showBluetoothSettings_: function() {
1565 $('bluetooth-devices').hidden = false;
1569 * Dectivates the Bluetooth settings section from the System settings page.
1572 hideBluetoothSettings_: function() {
1573 $('bluetooth-devices').hidden = true;
1577 * Sets the state of the checkbox indicating if Bluetooth is turned on. The
1578 * state of the "Find devices" button and the list of discovered devices may
1579 * also be affected by a change to the state.
1580 * @param {boolean} checked Flag Indicating if Bluetooth is turned on.
1583 setBluetoothState_: function(checked) {
1584 $('enable-bluetooth').checked = checked;
1585 $('bluetooth-paired-devices-list').parentNode.hidden = !checked;
1586 $('bluetooth-add-device').hidden = !checked;
1587 $('bluetooth-reconnect-device').hidden = !checked;
1588 // Flush list of previously discovered devices if bluetooth is turned off.
1590 $('bluetooth-paired-devices-list').clear();
1591 $('bluetooth-unpaired-devices-list').clear();
1593 chrome.send('getPairedBluetoothDevices');
1598 * Adds an element to the list of available Bluetooth devices. If an element
1599 * with a matching address is found, the existing element is updated.
1600 * @param {{name: string,
1603 * connected: boolean}} device
1604 * Decription of the Bluetooth device.
1607 addBluetoothDevice_: function(device) {
1608 var list = $('bluetooth-unpaired-devices-list');
1609 // Display the "connecting" (already paired or not yet paired) and the
1610 // paired devices in the same list.
1611 if (device.paired || device.connecting) {
1612 // Test to see if the device is currently in the unpaired list, in which
1613 // case it should be removed from that list.
1614 var index = $('bluetooth-unpaired-devices-list').find(device.address);
1615 if (index != undefined)
1616 $('bluetooth-unpaired-devices-list').deleteItemAtIndex(index);
1617 list = $('bluetooth-paired-devices-list');
1619 // Test to see if the device is currently in the paired list, in which
1620 // case it should be removed from that list.
1621 var index = $('bluetooth-paired-devices-list').find(device.address);
1622 if (index != undefined)
1623 $('bluetooth-paired-devices-list').deleteItemAtIndex(index);
1625 list.appendDevice(device);
1627 // One device can be in the process of pairing. If found, display
1628 // the Bluetooth pairing overlay.
1630 BluetoothPairing.showDialog(device);
1634 * Removes an element from the list of available devices.
1635 * @param {string} address Unique address of the device.
1638 removeBluetoothDevice_: function(address) {
1639 var index = $('bluetooth-unpaired-devices-list').find(address);
1640 if (index != undefined) {
1641 $('bluetooth-unpaired-devices-list').deleteItemAtIndex(index);
1643 index = $('bluetooth-paired-devices-list').find(address);
1644 if (index != undefined)
1645 $('bluetooth-paired-devices-list').deleteItemAtIndex(index);
1650 * Shows the overlay dialog for changing the user avatar image.
1653 showImagerPickerOverlay_: function() {
1654 OptionsPage.navigateToPage('changePicture');
1658 * Shows (or not) the "User" section of the settings page based on whether
1659 * any of the sub-sections are present (or not).
1662 maybeShowUserSection_: function() {
1663 $('sync-users-section').hidden =
1664 $('profiles-section').hidden &&
1665 $('sync-section').hidden &&
1666 $('profiles-supervised-dashboard-tip').hidden;
1670 //Forward public APIs to private implementations.
1672 'addBluetoothDevice',
1673 'enableCertificateButton',
1674 'enableFactoryResetSection',
1675 'getCurrentProfile',
1676 'getStartStopSyncButton',
1677 'hideBluetoothSettings',
1678 'notifyInitializationComplete',
1679 'removeBluetoothDevice',
1680 'removeCloudPrintConnectorSection',
1682 'setAccountPictureManaged',
1683 'setWallpaperManaged',
1684 'setAutoOpenFileTypesDisplayed',
1685 'setBluetoothState',
1687 'setNativeThemeButtonEnabled',
1688 'setHighContrastCheckboxState',
1689 'setMetricsReportingCheckboxState',
1690 'setMetricsReportingSettingVisibility',
1692 'setSpokenFeedbackCheckboxState',
1693 'setThemesResetButtonEnabled',
1694 'setVirtualKeyboardCheckboxState',
1695 'setupCloudPrintConnectorSection',
1696 'setupPageZoomSelector',
1697 'setupProxySettingsSection',
1698 'showBluetoothSettings',
1699 'showCreateProfileError',
1700 'showCreateProfileSuccess',
1701 'showCreateProfileWarning',
1702 'showHotwordSection',
1703 'showManagedUserImportError',
1704 'showManagedUserImportSuccess',
1705 'showMouseControls',
1706 'showTouchpadControls',
1707 'updateAccountPicture',
1708 'updateAutoLaunchState',
1709 'updateDefaultBrowserState',
1711 'updateManagesSupervisedUsers',
1712 'updateSearchEngines',
1713 'updateStartupPages',
1715 ].forEach(function(name) {
1716 BrowserOptions[name] = function() {
1717 var instance = BrowserOptions.getInstance();
1718 return instance[name + '_'].apply(instance, arguments);
1722 if (cr.isChromeOS) {
1724 * Returns username (canonical email) of the user logged in (ChromeOS only).
1725 * @return {string} user email.
1727 // TODO(jhawkins): Investigate the use case for this method.
1728 BrowserOptions.getLoggedInUsername = function() {
1729 return BrowserOptions.getInstance().username_;
1735 BrowserOptions: BrowserOptions