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 Page
= cr
.ui
.pageManager
.Page
;
8 var PageManager
= cr
.ui
.pageManager
.PageManager
;
9 var ArrayDataModel
= cr
.ui
.ArrayDataModel
;
10 var RepeatingButton
= cr
.ui
.RepeatingButton
;
11 var HotwordSearchSettingIndicator
= options
.HotwordSearchSettingIndicator
;
12 var NetworkPredictionOptions
= {
21 * Encapsulated handling of browser options page.
23 * @extends {cr.ui.pageManager.Page}
25 function BrowserOptions() {
26 Page
.call(this, 'settings', loadTimeData
.getString('settingsTitle'),
30 cr
.addSingletonGetter(BrowserOptions
);
33 * @param {HTMLElement} section The section to show or hide.
34 * @return {boolean} Whether the section should be shown.
37 BrowserOptions
.shouldShowSection_ = function(section
) {
38 // If the section is hidden or hiding, it should be shown.
39 return section
.style
.height
== '' || section
.style
.height
== '0px';
42 BrowserOptions
.prototype = {
43 __proto__
: Page
.prototype,
46 * Keeps track of whether the user is signed in or not.
53 * Indicates whether signing out is allowed or whether a complete profile
54 * wipe is required to remove the current enterprise account.
58 signoutAllowed_
: true,
61 * Keeps track of whether |onShowHomeButtonChanged_| has been called. See
62 * |onShowHomeButtonChanged_|.
66 onShowHomeButtonChangedCalled_
: false,
69 * Track if page initialization is complete. All C++ UI handlers have the
70 * chance to manipulate page content within their InitializePage methods.
71 * This flag is set to true after all initializers have been called.
75 initializationComplete_
: false,
78 initializePage: function() {
79 Page
.prototype.initializePage
.call(this);
82 if (window
.top
!= window
) {
83 // The options page is not in its own window.
84 document
.body
.classList
.add('uber-frame');
85 PageManager
.horizontalOffset
= 155;
88 // Ensure that navigation events are unblocked on uber page. A reload of
89 // the settings page while an overlay is open would otherwise leave uber
90 // page in a blocked state, where tab switching is not possible.
91 uber
.invokeMethodOnParent('stopInterceptingEvents');
93 window
.addEventListener('message', this.handleWindowMessage_
.bind(this));
95 if (loadTimeData
.getBoolean('allowAdvancedSettings')) {
96 $('advanced-settings-expander').onclick = function() {
98 BrowserOptions
.shouldShowSection_($('advanced-settings'));
100 chrome
.send('coreOptionsUserMetricsAction',
101 ['Options_ShowAdvancedSettings']);
103 self
.toggleSectionWithAnimation_(
104 $('advanced-settings'),
105 $('advanced-settings-container'));
107 // If the link was focused (i.e., it was activated using the keyboard)
108 // and it was used to show the section (rather than hiding it), focus
109 // the first element in the container.
110 if (document
.activeElement
=== $('advanced-settings-expander') &&
112 var focusElement
= $('advanced-settings-container').querySelector(
113 'button, input, list, select, a[href]');
115 focusElement
.focus();
119 $('advanced-settings-expander').hidden
= true;
120 $('advanced-settings').hidden
= true;
123 $('advanced-settings').addEventListener('webkitTransitionEnd',
124 this.updateAdvancedSettingsExpander_
.bind(this));
126 if (loadTimeData
.getBoolean('showVersion')) {
127 $('version-button').hidden
= false;
128 $('version-button').addEventListener('click', function() {
129 PageManager
.showPageByName('help');
130 chrome
.send('coreOptionsUserMetricsAction',
136 UIAccountTweaks
.applyGuestSessionVisibility(document
);
137 UIAccountTweaks
.applyPublicSessionVisibility(document
);
138 if (loadTimeData
.getBoolean('secondaryUser'))
139 $('secondary-user-banner').hidden
= false;
142 // Sync (Sign in) section.
143 this.updateSyncState_(loadTimeData
.getValue('syncData'));
145 $('start-stop-sync').onclick = function(event
) {
146 if (self
.signedIn_
) {
147 if (self
.signoutAllowed_
)
148 SyncSetupOverlay
.showStopSyncingUI();
150 chrome
.send('showDisconnectManagedProfileDialog');
151 } else if (cr
.isChromeOS
) {
152 SyncSetupOverlay
.showSetupUI();
154 SyncSetupOverlay
.startSignIn();
157 $('customize-sync').onclick = function(event
) {
158 SyncSetupOverlay
.showSetupUI();
161 // Internet connection section (ChromeOS only).
163 options
.network
.NetworkList
.decorate($('network-list'));
164 // Show that the network settings are shared if this is a secondary user
165 // in a multi-profile session.
166 if (loadTimeData
.getBoolean('secondaryUser')) {
167 var networkIndicator
= document
.querySelector(
168 '#network-section-header > .controlled-setting-indicator');
169 networkIndicator
.setAttribute('controlled-by', 'shared');
170 networkIndicator
.location
= cr
.ui
.ArrowLocation
.TOP_START
;
172 options
.network
.NetworkList
.refreshNetworkData(
173 loadTimeData
.getValue('networkData'));
176 // On Startup section.
177 Preferences
.getInstance().addEventListener('session.restore_on_startup',
178 this.onRestoreOnStartupChanged_
.bind(this));
179 Preferences
.getInstance().addEventListener(
180 'session.startup_urls',
182 $('startup-set-pages').disabled
= event
.value
.disabled
;
185 $('startup-set-pages').onclick = function() {
186 PageManager
.showPageByName('startup');
189 // Appearance section.
190 Preferences
.getInstance().addEventListener('browser.show_home_button',
191 this.onShowHomeButtonChanged_
.bind(this));
193 Preferences
.getInstance().addEventListener('homepage',
194 this.onHomePageChanged_
.bind(this));
195 Preferences
.getInstance().addEventListener('homepage_is_newtabpage',
196 this.onHomePageIsNtpChanged_
.bind(this));
198 $('change-home-page').onclick = function(event
) {
199 PageManager
.showPageByName('homePageOverlay');
200 chrome
.send('coreOptionsUserMetricsAction',
201 ['Options_Homepage_ShowSettings']);
204 var hotwordIndicator
= $('hotword-search-setting-indicator');
205 HotwordSearchSettingIndicator
.decorate(hotwordIndicator
);
206 chrome
.send('requestHotwordAvailable');
208 if ($('set-wallpaper')) {
209 $('set-wallpaper').onclick = function(event
) {
210 chrome
.send('openWallpaperManager');
211 chrome
.send('coreOptionsUserMetricsAction',
212 ['Options_OpenWallpaperManager']);
216 $('themes-gallery').onclick = function(event
) {
217 window
.open(loadTimeData
.getString('themesGalleryURL'));
218 chrome
.send('coreOptionsUserMetricsAction',
219 ['Options_ThemesGallery']);
221 $('themes-reset').onclick = function(event
) {
222 chrome
.send('themesReset');
225 if (loadTimeData
.getBoolean('profileIsSupervised')) {
226 if ($('themes-native-button')) {
227 $('themes-native-button').disabled
= true;
228 $('themes-native-button').hidden
= true;
230 // Supervised users have just one default theme, even on Linux. So use
231 // the same button for Linux as for the other platforms.
232 $('themes-reset').textContent
= loadTimeData
.getString('themesReset');
235 // Device section (ChromeOS only).
237 $('battery-button').onclick = function(evt
) {
238 WebsiteSettingsManager
.showWebsiteSettings('battery');
240 $('stored-data-button').onclick = function(evt
) {
241 WebsiteSettingsManager
.showWebsiteSettings('storage');
243 $('keyboard-settings-button').onclick = function(evt
) {
244 PageManager
.showPageByName('keyboard-overlay');
245 chrome
.send('coreOptionsUserMetricsAction',
246 ['Options_ShowKeyboardSettings']);
248 $('pointer-settings-button').onclick = function(evt
) {
249 PageManager
.showPageByName('pointer-overlay');
250 chrome
.send('coreOptionsUserMetricsAction',
251 ['Options_ShowTouchpadSettings']);
256 $('manage-default-search-engines').onclick = function(event
) {
257 PageManager
.showPageByName('searchEngines');
258 chrome
.send('coreOptionsUserMetricsAction',
259 ['Options_ManageSearchEngines']);
261 $('default-search-engine').addEventListener('change',
262 this.setDefaultSearchEngine_
);
265 if (loadTimeData
.valueExists('profilesInfo')) {
266 $('profiles-section').hidden
= false;
267 this.maybeShowUserSection_();
269 var profilesList
= $('profiles-list');
270 options
.browser_options
.ProfileList
.decorate(profilesList
);
271 profilesList
.autoExpands
= true;
273 // The profiles info data in |loadTimeData| might be stale.
274 this.setProfilesInfo_(loadTimeData
.getValue('profilesInfo'));
275 chrome
.send('requestProfilesInfo');
277 profilesList
.addEventListener('change',
278 this.setProfileViewButtonsStatus_
);
279 $('profiles-create').onclick = function(event
) {
280 ManageProfileOverlay
.showCreateDialog();
282 if (OptionsPage
.isSettingsApp()) {
283 $('profiles-app-list-switch').onclick = function(event
) {
284 var selectedProfile
= self
.getSelectedProfileItem_();
285 chrome
.send('switchAppListProfile', [selectedProfile
.filePath
]);
288 $('profiles-manage').onclick = function(event
) {
289 ManageProfileOverlay
.showManageDialog();
291 $('profiles-delete').onclick = function(event
) {
292 var selectedProfile
= self
.getSelectedProfileItem_();
294 ManageProfileOverlay
.showDeleteDialog(selectedProfile
);
296 if (loadTimeData
.getBoolean('profileIsSupervised')) {
297 $('profiles-create').disabled
= true;
298 $('profiles-delete').disabled
= true;
299 $('profiles-list').canDeleteItems
= false;
304 // Username (canonical email) of the currently logged in user or
305 // |kGuestUser| if a guest session is active.
306 this.username_
= loadTimeData
.getString('username');
308 this.updateAccountPicture_();
310 $('account-picture').onclick
= this.showImagerPickerOverlay_
;
311 $('change-picture-caption').onclick
= this.showImagerPickerOverlay_
;
313 $('manage-accounts-button').onclick = function(event
) {
314 PageManager
.showPageByName('accounts');
315 chrome
.send('coreOptionsUserMetricsAction',
316 ['Options_ManageAccounts']);
319 $('import-data').onclick = function(event
) {
320 ImportDataOverlay
.show();
321 chrome
.send('coreOptionsUserMetricsAction', ['Import_ShowDlg']);
324 if ($('themes-native-button')) {
325 $('themes-native-button').onclick = function(event
) {
326 chrome
.send('themesSetNative');
331 // Date and time section (CrOS only).
332 if ($('set-time-button'))
333 $('set-time-button').onclick
= this.handleSetTime_
.bind(this);
335 // Default browser section.
336 if (!cr
.isChromeOS
) {
337 if (!loadTimeData
.getBoolean('showSetDefault')) {
338 $('set-default-browser-section').hidden
= true;
340 $('set-as-default-browser').onclick = function(event
) {
341 chrome
.send('becomeDefaultBrowser');
344 $('auto-launch').onclick
= this.handleAutoLaunchChanged_
;
348 $('privacyContentSettingsButton').onclick = function(event
) {
349 PageManager
.showPageByName('content');
350 OptionsPage
.showTab($('cookies-nav-tab'));
351 chrome
.send('coreOptionsUserMetricsAction',
352 ['Options_ContentSettings']);
354 $('privacyClearDataButton').onclick = function(event
) {
355 PageManager
.showPageByName('clearBrowserData');
356 chrome
.send('coreOptionsUserMetricsAction', ['Options_ClearData']);
358 $('privacyClearDataButton').hidden
= OptionsPage
.isSettingsApp();
359 // 'metricsReportingEnabled' element is only present on Chrome branded
360 // builds, and the 'metricsReportingCheckboxAction' message is only
361 // handled on ChromeOS.
362 if ($('metricsReportingEnabled') && cr
.isChromeOS
) {
363 $('metricsReportingEnabled').onclick = function(event
) {
364 chrome
.send('metricsReportingCheckboxAction',
365 [String(event
.currentTarget
.checked
)]);
368 if ($('metricsReportingEnabled') && !cr
.isChromeOS
) {
369 // The localized string has the | symbol on each side of the text that
370 // needs to be made into a button to restart Chrome. We parse the text
371 // and build the button from that.
372 var restartTextFragments
=
373 loadTimeData
.getString('metricsReportingResetRestart').split('|');
374 // Assume structure is something like "starting text |link text| ending
375 // text" where both starting text and ending text may or may not be
376 // present, but the split should always be in three pieces.
377 var restartElements
=
378 $('metrics-reporting-reset-restart').querySelectorAll('*');
379 for (var i
= 0; i
< restartTextFragments
.length
; i
++) {
380 restartElements
[i
].textContent
= restartTextFragments
[i
];
382 restartElements
[1].onclick = function(event
) {
383 chrome
.send('restartBrowser');
385 // Attach the listener for updating the checkbox and restart button.
386 var updateMetricsRestartButton = function() {
387 $('metrics-reporting-reset-restart').hidden
=
388 loadTimeData
.getBoolean('metricsReportingEnabledAtStart') ==
389 $('metricsReportingEnabled').checked
;
391 $('metricsReportingEnabled').onclick = function(event
) {
392 chrome
.send('metricsReportingCheckboxChanged',
393 [Boolean(event
.currentTarget
.checked
)]);
394 updateMetricsRestartButton();
396 $('metricsReportingEnabled').checked
=
397 loadTimeData
.getBoolean('metricsReportingEnabledAtStart');
398 updateMetricsRestartButton();
400 $('networkPredictionOptions').onchange = function(event
) {
401 var value
= (event
.target
.checked
?
402 NetworkPredictionOptions
.WIFI_ONLY
:
403 NetworkPredictionOptions
.NEVER
);
404 var metric
= event
.target
.metric
;
405 Preferences
.setIntegerPref(
406 'net.network_prediction_options',
412 // Bluetooth (CrOS only).
414 options
.system
.bluetooth
.BluetoothDeviceList
.decorate(
415 $('bluetooth-paired-devices-list'));
417 $('bluetooth-add-device').onclick
=
418 this.handleAddBluetoothDevice_
.bind(this);
420 $('enable-bluetooth').onchange = function(event
) {
421 var state
= $('enable-bluetooth').checked
;
422 chrome
.send('bluetoothEnableChange', [Boolean(state
)]);
425 $('bluetooth-reconnect-device').onclick = function(event
) {
426 var device
= $('bluetooth-paired-devices-list').selectedItem
;
427 var address
= device
.address
;
428 chrome
.send('updateBluetoothDevice', [address
, 'connect']);
429 PageManager
.closeOverlay();
432 $('bluetooth-paired-devices-list').addEventListener('change',
434 var item
= $('bluetooth-paired-devices-list').selectedItem
;
435 var disabled
= !item
|| item
.connected
|| !item
.connectable
;
436 $('bluetooth-reconnect-device').disabled
= disabled
;
440 // Passwords and Forms section.
441 $('autofill-settings').onclick = function(event
) {
442 PageManager
.showPageByName('autofill');
443 chrome
.send('coreOptionsUserMetricsAction',
444 ['Options_ShowAutofillSettings']);
446 $('manage-passwords').onclick = function(event
) {
447 PageManager
.showPageByName('passwords');
448 OptionsPage
.showTab($('passwords-nav-tab'));
449 chrome
.send('coreOptionsUserMetricsAction',
450 ['Options_ShowPasswordManager']);
452 if (cr
.isChromeOS
&& UIAccountTweaks
.loggedInAsGuest()) {
453 // Disable and turn off Autofill in guest mode.
454 var autofillEnabled
= $('autofill-enabled');
455 autofillEnabled
.disabled
= true;
456 autofillEnabled
.checked
= false;
457 cr
.dispatchSimpleEvent(autofillEnabled
, 'change');
458 $('autofill-settings').disabled
= true;
460 // Disable and turn off Password Manager in guest mode.
461 var passwordManagerEnabled
= $('password-manager-enabled');
462 passwordManagerEnabled
.disabled
= true;
463 passwordManagerEnabled
.checked
= false;
464 cr
.dispatchSimpleEvent(passwordManagerEnabled
, 'change');
465 $('manage-passwords').disabled
= true;
469 $('mac-passwords-warning').hidden
=
470 !loadTimeData
.getBoolean('multiple_profiles');
474 if (!cr
.isChromeOS
) {
475 $('proxiesConfigureButton').onclick = function(event
) {
476 chrome
.send('showNetworkProxySettings');
480 // Device control section.
482 UIAccountTweaks
.currentUserIsOwner() &&
483 loadTimeData
.getBoolean('consumerManagementEnabled')) {
484 $('device-control-section').hidden
= false;
485 $('consumer-management-button').onclick = function(event
) {
486 PageManager
.showPageByName('consumer-management-overlay');
490 // Easy Unlock section.
491 if (loadTimeData
.getBoolean('easyUnlockAllowed')) {
492 $('easy-unlock-section').hidden
= false;
493 $('easy-unlock-setup-button').onclick = function(event
) {
494 chrome
.send('launchEasyUnlockSetup');
496 $('easy-unlock-turn-off-button').onclick = function(event
) {
497 PageManager
.showPageByName('easyUnlockTurnOffOverlay');
501 // Website Settings section.
502 if (loadTimeData
.getBoolean('websiteSettingsManagerEnabled')) {
503 $('website-settings-section').hidden
= false;
504 $('website-management-button').onclick = function(event
) {
505 PageManager
.showPageByName('websiteSettings');
509 // Web Content section.
510 $('fontSettingsCustomizeFontsButton').onclick = function(event
) {
511 PageManager
.showPageByName('fonts');
512 chrome
.send('coreOptionsUserMetricsAction', ['Options_FontSettings']);
514 $('defaultFontSize').onchange = function(event
) {
515 var value
= event
.target
.options
[event
.target
.selectedIndex
].value
;
516 Preferences
.setIntegerPref(
517 'webkit.webprefs.default_fixed_font_size',
518 value
- OptionsPage
.SIZE_DIFFERENCE_FIXED_STANDARD
, true);
519 chrome
.send('defaultFontSizeAction', [String(value
)]);
521 $('defaultZoomFactor').onchange = function(event
) {
522 chrome
.send('defaultZoomFactorAction',
523 [String(event
.target
.options
[event
.target
.selectedIndex
].value
)]);
526 // Languages section.
527 var showLanguageOptions = function(event
) {
528 PageManager
.showPageByName('languages');
529 chrome
.send('coreOptionsUserMetricsAction',
530 ['Options_LanuageAndSpellCheckSettings']);
532 $('language-button').onclick
= showLanguageOptions
;
533 $('manage-languages').onclick
= showLanguageOptions
;
535 // Downloads section.
536 Preferences
.getInstance().addEventListener('download.default_directory',
537 this.onDefaultDownloadDirectoryChanged_
.bind(this));
538 $('downloadLocationChangeButton').onclick = function(event
) {
539 chrome
.send('selectDownloadLocation');
542 $('disable-drive-row').hidden
=
543 UIAccountTweaks
.loggedInAsSupervisedUser();
545 $('autoOpenFileTypesResetToDefault').onclick = function(event
) {
546 chrome
.send('autoOpenFileTypesAction');
549 // HTTPS/SSL section.
550 if (cr
.isWindows
|| cr
.isMac
) {
551 $('certificatesManageButton').onclick = function(event
) {
552 chrome
.send('showManageSSLCertificates');
555 $('certificatesManageButton').onclick = function(event
) {
556 PageManager
.showPageByName('certificates');
557 chrome
.send('coreOptionsUserMetricsAction',
558 ['Options_ManageSSLCertificates']);
562 if (loadTimeData
.getBoolean('cloudPrintShowMDnsOptions')) {
563 $('cloudprint-options-mdns').hidden
= false;
564 $('cloudPrintDevicesPageButton').onclick = function() {
565 chrome
.send('showCloudPrintDevicesPage');
569 // Accessibility section (CrOS only).
571 var updateAccessibilitySettingsButton = function() {
572 $('accessibility-settings').hidden
=
573 !($('accessibility-spoken-feedback-check').checked
);
575 Preferences
.getInstance().addEventListener(
576 'settings.accessibility',
577 updateAccessibilitySettingsButton
);
578 $('accessibility-learn-more').onclick = function(unused_event
) {
579 window
.open(loadTimeData
.getString('accessibilityLearnMoreURL'));
580 chrome
.send('coreOptionsUserMetricsAction',
581 ['Options_AccessibilityLearnMore']);
583 $('accessibility-settings-button').onclick = function(unused_event
) {
584 window
.open(loadTimeData
.getString('accessibilitySettingsURL'));
586 $('accessibility-spoken-feedback-check').onchange = function(
588 chrome
.send('spokenFeedbackChange',
589 [$('accessibility-spoken-feedback-check').checked
]);
590 updateAccessibilitySettingsButton();
592 updateAccessibilitySettingsButton();
594 $('accessibility-high-contrast-check').onchange = function(
596 chrome
.send('highContrastChange',
597 [$('accessibility-high-contrast-check').checked
]);
600 var updateDelayDropdown = function() {
601 $('accessibility-autoclick-dropdown').disabled
=
602 !$('accessibility-autoclick-check').checked
;
604 Preferences
.getInstance().addEventListener(
605 $('accessibility-autoclick-check').getAttribute('pref'),
606 updateDelayDropdown
);
609 // Display management section (CrOS only).
611 $('display-options').onclick = function(event
) {
612 PageManager
.showPageByName('display');
613 chrome
.send('coreOptionsUserMetricsAction',
614 ['Options_Display']);
618 // Factory reset section (CrOS only).
620 $('factory-reset-restart').onclick = function(event
) {
621 PageManager
.showPageByName('factoryResetData');
622 chrome
.send('onPowerwashDialogShow');
627 if (!cr
.isChromeOS
) {
628 var updateGpuRestartButton = function() {
629 $('gpu-mode-reset-restart').hidden
=
630 loadTimeData
.getBoolean('gpuEnabledAtStart') ==
631 $('gpu-mode-checkbox').checked
;
633 Preferences
.getInstance().addEventListener(
634 $('gpu-mode-checkbox').getAttribute('pref'),
635 updateGpuRestartButton
);
636 $('gpu-mode-reset-restart-button').onclick = function(event
) {
637 chrome
.send('restartBrowser');
639 updateGpuRestartButton();
642 // Reset profile settings section.
643 $('reset-profile-settings').onclick = function(event
) {
644 PageManager
.showPageByName('resetProfileSettings');
647 // Extension controlled UI.
648 this.addExtensionControlledBox_('search-section-content',
649 'search-engine-controlled',
651 this.addExtensionControlledBox_('extension-controlled-container',
652 'homepage-controlled',
654 this.addExtensionControlledBox_('startup-section-content',
655 'startpage-controlled',
657 this.addExtensionControlledBox_('newtab-section-content',
660 this.addExtensionControlledBox_('proxy-section-content',
664 document
.body
.addEventListener('click', function(e
) {
665 var button
= findAncestor(e
.target
, function(el
) {
666 return el
.tagName
== 'BUTTON' &&
667 el
.dataset
.extensionId
!== undefined &&
668 el
.dataset
.extensionId
.length
;
671 chrome
.send('disableExtension', [button
.dataset
.extensionId
]);
676 didShowPage: function() {
677 $('search-field').focus();
681 * Called after all C++ UI handlers have called InitializePage to notify
682 * that initialization is complete.
685 notifyInitializationComplete_: function() {
686 this.initializationComplete_
= true;
687 cr
.dispatchSimpleEvent(document
, 'initializationComplete');
691 * Event listener for the 'session.restore_on_startup' pref.
692 * @param {Event} event The preference change event.
695 onRestoreOnStartupChanged_: function(event
) {
696 /** @const */ var showHomePageValue
= 0;
698 if (event
.value
.value
== showHomePageValue
) {
699 // If the user previously selected "Show the homepage", the
700 // preference will already be migrated to "Open a specific page". So
701 // the only way to reach this code is if the 'restore on startup'
702 // preference is managed.
703 assert(event
.value
.controlledBy
);
705 // Select "open the following pages" and lock down the list of URLs
706 // to reflect the intention of the policy.
707 $('startup-show-pages').checked
= true;
708 StartupOverlay
.getInstance().setControlsDisabled(true);
710 // Re-enable the controls in the startup overlay if necessary.
711 StartupOverlay
.getInstance().updateControlStates();
716 * Handler for messages sent from the main uber page.
717 * @param {Event} e The 'message' event from the uber page.
720 handleWindowMessage_: function(e
) {
721 if (e
.data
.method
== 'frameSelected')
722 $('search-field').focus();
726 * Animatedly changes height |from| a px number |to| a px number.
727 * @param {HTMLElement} section The section to animate.
728 * @param {HTMLElement} container The container of |section|.
729 * @param {boolean} showing Whether to go from 0 -> container height or
730 * container height -> 0.
733 animatedSectionHeightChange_: function(section
, container
, showing
) {
734 // If the section is already animating, dispatch a synthetic transition
735 // end event as the upcoming code will cancel the current one.
736 if (section
.classList
.contains('sliding'))
737 cr
.dispatchSimpleEvent(section
, 'webkitTransitionEnd');
739 this.addTransitionEndListener_(section
);
741 section
.hidden
= false;
742 section
.style
.height
= (showing
? 0 : container
.offsetHeight
) + 'px';
743 section
.classList
.add('sliding');
745 // Force a style recalc before starting the animation.
746 /** @suppress {suspiciousCode} */
747 section
.offsetHeight
;
749 section
.style
.height
= (showing
? container
.offsetHeight
: 0) + 'px';
753 * Shows the given section.
754 * @param {HTMLElement} section The section to be shown.
755 * @param {HTMLElement} container The container for the section. Must be
756 * inside of |section|.
757 * @param {boolean} animate Indicate if the expansion should be animated.
760 showSection_: function(section
, container
, animate
) {
761 // Delay starting the transition if animating so that hidden change will
764 this.animatedSectionHeightChange_(section
, container
, true);
766 section
.hidden
= false;
767 section
.style
.height
= 'auto';
772 * Shows the given section, with animation.
773 * @param {HTMLElement} section The section to be shown.
774 * @param {HTMLElement} container The container for the section. Must be
775 * inside of |section|.
778 showSectionWithAnimation_: function(section
, container
) {
779 this.showSection_(section
, container
, /* animate */ true);
783 * Hides the given |section| with animation.
784 * @param {HTMLElement} section The section to be hidden.
785 * @param {HTMLElement} container The container for the section. Must be
786 * inside of |section|.
789 hideSectionWithAnimation_: function(section
, container
) {
790 this.animatedSectionHeightChange_(section
, container
, false);
794 * Toggles the visibility of |section| in an animated way.
795 * @param {HTMLElement} section The section to be toggled.
796 * @param {HTMLElement} container The container for the section. Must be
797 * inside of |section|.
800 toggleSectionWithAnimation_: function(section
, container
) {
801 if (BrowserOptions
.shouldShowSection_(section
))
802 this.showSectionWithAnimation_(section
, container
);
804 this.hideSectionWithAnimation_(section
, container
);
808 * Scrolls the settings page to make the section visible auto-expanding
809 * advanced settings if required. The transition is not animated. This
810 * method is used to ensure that a section associated with an overlay
811 * is visible when the overlay is closed.
812 * @param {!Element} section The section to make visible.
815 scrollToSection_: function(section
) {
816 var advancedSettings
= $('advanced-settings');
817 var container
= $('advanced-settings-container');
818 var expander
= $('advanced-settings-expander');
819 if (!expander
.hidden
&&
820 advancedSettings
.hidden
&&
821 section
.parentNode
== container
) {
822 this.showSection_($('advanced-settings'),
823 $('advanced-settings-container'),
824 /* animate */ false);
825 this.updateAdvancedSettingsExpander_();
828 if (!this.initializationComplete_
) {
830 var callback = function() {
831 document
.removeEventListener('initializationComplete', callback
);
832 self
.scrollToSection_(section
);
834 document
.addEventListener('initializationComplete', callback
);
838 var pageContainer
= $('page-container');
839 // pageContainer.offsetTop is relative to the screen.
840 var pageTop
= pageContainer
.offsetTop
;
841 var sectionBottom
= section
.offsetTop
+ section
.offsetHeight
;
842 // section.offsetTop is relative to the 'page-container'.
843 var sectionTop
= section
.offsetTop
;
844 if (pageTop
+ sectionBottom
> document
.body
.scrollHeight
||
845 pageTop
+ sectionTop
< 0) {
846 // Currently not all layout updates are guaranteed to precede the
847 // initializationComplete event (for example 'set-as-default-browser'
848 // button) leaving some uncertainty in the optimal scroll position.
849 // The section is placed approximately in the middle of the screen.
850 var top
= Math
.min(0, document
.body
.scrollHeight
/ 2 - sectionBottom
);
851 pageContainer
.style
.top
= top
+ 'px';
852 pageContainer
.oldScrollTop
= -top
;
857 * Adds a |webkitTransitionEnd| listener to the given section so that
858 * it can be animated. The listener will only be added to a given section
859 * once, so this can be called as multiple times.
860 * @param {HTMLElement} section The section to be animated.
863 addTransitionEndListener_: function(section
) {
864 if (section
.hasTransitionEndListener_
)
867 section
.addEventListener('webkitTransitionEnd',
868 this.onTransitionEnd_
.bind(this));
869 section
.hasTransitionEndListener_
= true;
873 * Called after an animation transition has ended.
874 * @param {Event} event The webkitTransitionEnd event. NOTE: May be
878 onTransitionEnd_: function(event
) {
879 if (event
.propertyName
&& event
.propertyName
!= 'height') {
880 // If not a synthetic event or a real transition we care about, bail.
884 var section
= event
.target
;
885 section
.classList
.remove('sliding');
887 if (!event
.propertyName
) {
888 // Only real transitions past this point.
892 if (section
.style
.height
== '0px') {
893 // Hide the content so it can't get tab focus.
894 section
.hidden
= true;
895 section
.style
.height
= '';
897 // Set the section height to 'auto' to allow for size changes
898 // (due to font change or dynamic content).
899 section
.style
.height
= 'auto';
904 updateAdvancedSettingsExpander_: function() {
905 var expander
= $('advanced-settings-expander');
906 if (BrowserOptions
.shouldShowSection_($('advanced-settings')))
907 expander
.textContent
= loadTimeData
.getString('showAdvancedSettings');
909 expander
.textContent
= loadTimeData
.getString('hideAdvancedSettings');
913 * Updates the sync section with the given state.
914 * @param {Object} syncData A bunch of data records that describe the status
915 * of the sync system.
918 updateSyncState_: function(syncData
) {
919 if (!syncData
.signinAllowed
&&
920 (!syncData
.supervisedUser
|| !cr
.isChromeOS
)) {
921 $('sync-section').hidden
= true;
922 this.maybeShowUserSection_();
926 $('sync-section').hidden
= false;
927 this.maybeShowUserSection_();
929 if (cr
.isChromeOS
&& syncData
.supervisedUser
) {
930 var subSection
= $('sync-section').firstChild
;
932 if (subSection
.nodeType
== Node
.ELEMENT_NODE
)
933 subSection
.hidden
= true;
934 subSection
= subSection
.nextSibling
;
937 $('account-picture-wrapper').hidden
= false;
938 $('sync-general').hidden
= false;
939 $('sync-status').hidden
= true;
944 // If the user gets signed out while the advanced sync settings dialog is
945 // visible, say, due to a dashboard clear, close the dialog.
946 // However, if the user gets signed out as a result of abandoning first
947 // time sync setup, do not call closeOverlay as it will redirect the
948 // browser to the main settings page and override any in-progress
949 // user-initiated navigation. See crbug.com/278030.
950 // Note: SyncSetupOverlay.closeOverlay is a no-op if the overlay is
952 if (this.signedIn_
&& !syncData
.signedIn
&& !syncData
.setupInProgress
)
953 SyncSetupOverlay
.closeOverlay();
955 this.signedIn_
= syncData
.signedIn
;
957 // Display the "advanced settings" button if we're signed in and sync is
958 // not managed/disabled. If the user is signed in, but sync is disabled,
959 // this button is used to re-enable sync.
960 var customizeSyncButton
= $('customize-sync');
961 customizeSyncButton
.hidden
= !this.signedIn_
||
963 !syncData
.syncSystemEnabled
;
965 // Only modify the customize button's text if the new text is different.
966 // Otherwise, it can affect search-highlighting in the settings page.
967 // See http://crbug.com/268265.
968 var customizeSyncButtonNewText
= syncData
.setupCompleted
?
969 loadTimeData
.getString('customizeSync') :
970 loadTimeData
.getString('syncButtonTextStart');
971 if (customizeSyncButton
.textContent
!= customizeSyncButtonNewText
)
972 customizeSyncButton
.textContent
= customizeSyncButtonNewText
;
974 // Disable the "sign in" button if we're currently signing in, or if we're
975 // already signed in and signout is not allowed.
976 var signInButton
= $('start-stop-sync');
977 signInButton
.disabled
= syncData
.setupInProgress
;
978 this.signoutAllowed_
= syncData
.signoutAllowed
;
979 if (!syncData
.signoutAllowed
)
980 $('start-stop-sync-indicator').setAttribute('controlled-by', 'policy');
982 $('start-stop-sync-indicator').removeAttribute('controlled-by');
984 // Hide the "sign in" button on Chrome OS, and show it on desktop Chrome
985 // (except for supervised users, which can't change their signed-in
987 signInButton
.hidden
= cr
.isChromeOS
|| syncData
.supervisedUser
;
989 signInButton
.textContent
=
991 loadTimeData
.getString('syncButtonTextStop') :
992 syncData
.setupInProgress
?
993 loadTimeData
.getString('syncButtonTextInProgress') :
994 loadTimeData
.getString('syncButtonTextSignIn');
995 $('start-stop-sync-indicator').hidden
= signInButton
.hidden
;
997 // TODO(estade): can this just be textContent?
998 $('sync-status-text').innerHTML
= syncData
.statusText
;
999 var statusSet
= syncData
.statusText
.length
!= 0;
1000 $('sync-overview').hidden
=
1002 (cr
.isChromeOS
&& UIAccountTweaks
.loggedInAsPublicAccount());
1003 $('sync-status').hidden
= !statusSet
;
1005 $('sync-action-link').textContent
= syncData
.actionLinkText
;
1006 // Don't show the action link if it is empty or undefined.
1007 $('sync-action-link').hidden
= syncData
.actionLinkText
.length
== 0;
1008 $('sync-action-link').disabled
= syncData
.managed
||
1009 !syncData
.syncSystemEnabled
;
1011 // On Chrome OS, sign out the user and sign in again to get fresh
1012 // credentials on auth errors.
1013 $('sync-action-link').onclick = function(event
) {
1014 if (cr
.isChromeOS
&& syncData
.hasError
)
1015 SyncSetupOverlay
.doSignOutOnAuthError();
1017 SyncSetupOverlay
.showSetupUI();
1020 if (syncData
.hasError
)
1021 $('sync-status').classList
.add('sync-error');
1023 $('sync-status').classList
.remove('sync-error');
1025 // Disable the "customize / set up sync" button if sync has an
1026 // unrecoverable error. Also disable the button if sync has not been set
1027 // up and the user is being presented with a link to re-auth.
1028 // See crbug.com/289791.
1029 customizeSyncButton
.disabled
=
1030 syncData
.hasUnrecoverableError
||
1031 (!syncData
.setupCompleted
&& !$('sync-action-link').hidden
);
1035 * Update the UI depending on whether the current profile has a pairing for
1037 * @param {boolean} hasPairing True if the current profile has a pairing.
1039 updateEasyUnlock_: function(hasPairing
) {
1040 $('easy-unlock-setup').hidden
= hasPairing
;
1041 $('easy-unlock-enable').hidden
= !hasPairing
;
1042 if (!hasPairing
&& EasyUnlockTurnOffOverlay
.getInstance().visible
) {
1043 EasyUnlockTurnOffOverlay
.dismiss();
1048 * Update the UI depending on whether the current profile manages any
1050 * @param {boolean} show True if the current profile manages any supervised
1053 updateManagesSupervisedUsers_: function(show
) {
1054 $('profiles-supervised-dashboard-tip').hidden
= !show
;
1055 this.maybeShowUserSection_();
1059 * Get the start/stop sync button DOM element. Used for testing.
1060 * @return {DOMElement} The start/stop sync button.
1063 getStartStopSyncButton_: function() {
1064 return $('start-stop-sync');
1068 * Event listener for the 'show home button' preference. Shows/hides the
1069 * UI for changing the home page with animation, unless this is the first
1070 * time this function is called, in which case there is no animation.
1071 * @param {Event} event The preference change event.
1073 onShowHomeButtonChanged_: function(event
) {
1074 var section
= $('change-home-page-section');
1075 if (this.onShowHomeButtonChangedCalled_
) {
1076 var container
= $('change-home-page-section-container');
1077 if (event
.value
.value
)
1078 this.showSectionWithAnimation_(section
, container
);
1080 this.hideSectionWithAnimation_(section
, container
);
1082 section
.hidden
= !event
.value
.value
;
1083 this.onShowHomeButtonChangedCalled_
= true;
1088 * Activates the Hotword section from the System settings page.
1089 * @param {boolean} opt_enabled Current preference state for hotwording.
1090 * @param {string} opt_error The error message to display.
1093 showHotwordSection_: function(opt_enabled
, opt_error
) {
1094 $('hotword-search').hidden
= false;
1095 $('hotword-search-setting-indicator').setError(opt_error
);
1096 if (opt_enabled
&& opt_error
)
1097 $('hotword-search-setting-indicator').updateBasedOnError();
1101 * Activates the Audio History and Always-On Hotword sections from the
1102 * System settings page.
1105 showHotwordAlwaysOnSection_: function() {
1106 $('voice-section-title').hidden
= false;
1107 $('hotword-always-on-search').hidden
= false;
1108 $('audio-logging').hidden
= false;
1112 * Event listener for the 'homepage is NTP' preference. Updates the label
1113 * next to the 'Change' button.
1114 * @param {Event} event The preference change event.
1116 onHomePageIsNtpChanged_: function(event
) {
1117 if (!event
.value
.uncommitted
) {
1118 $('home-page-url').hidden
= event
.value
.value
;
1119 $('home-page-ntp').hidden
= !event
.value
.value
;
1124 * Event listener for changes to the homepage preference. Updates the label
1125 * next to the 'Change' button.
1126 * @param {Event} event The preference change event.
1128 onHomePageChanged_: function(event
) {
1129 if (!event
.value
.uncommitted
)
1130 $('home-page-url').textContent
= this.stripHttp_(event
.value
.value
);
1134 * Removes the 'http://' from a URL, like the omnibox does. If the string
1135 * doesn't start with 'http://' it is returned unchanged.
1136 * @param {string} url The url to be processed
1137 * @return {string} The url with the 'http://' removed.
1139 stripHttp_: function(url
) {
1140 return url
.replace(/^http:\/\//, '');
1144 * Shows the autoLaunch preference and initializes its checkbox value.
1145 * @param {boolean} enabled Whether autolaunch is enabled or or not.
1148 updateAutoLaunchState_: function(enabled
) {
1149 $('auto-launch-option').hidden
= false;
1150 $('auto-launch').checked
= enabled
;
1154 * Called when the value of the download.default_directory preference
1156 * @param {Event} event Change event.
1159 onDefaultDownloadDirectoryChanged_: function(event
) {
1160 $('downloadLocationPath').value
= event
.value
.value
;
1161 if (cr
.isChromeOS
) {
1162 // On ChromeOS, replace /special/drive-<hash>/root with "Google Drive"
1163 // for remote files, /home/chronos/user/Downloads or
1164 // /home/chronos/u-<hash>/Downloads with "Downloads" for local paths,
1165 // and '/' with ' \u203a ' (angled quote sign) everywhere. The modified
1166 // path is used only for display purpose.
1167 var path
= $('downloadLocationPath').value
;
1168 path
= path
.replace(/^\/special\/drive[^\/]*\/root/, 'Google Drive');
1169 path
= path
.replace(/^\/home\/chronos\/(user|u-[^\/]*)\//, '');
1170 path
= path
.replace(/\//g, ' \u203a ');
1171 $('downloadLocationPath').value
= path
;
1173 $('download-location-label').classList
.toggle('disabled',
1174 event
.value
.disabled
);
1175 $('downloadLocationChangeButton').disabled
= event
.value
.disabled
;
1179 * Update the Default Browsers section based on the current state.
1180 * @param {string} statusString Description of the current default state.
1181 * @param {boolean} isDefault Whether or not the browser is currently
1183 * @param {boolean} canBeDefault Whether or not the browser can be default.
1186 updateDefaultBrowserState_: function(statusString
, isDefault
,
1188 if (!cr
.isChromeOS
) {
1189 var label
= $('default-browser-state');
1190 label
.textContent
= statusString
;
1192 $('set-as-default-browser').hidden
= !canBeDefault
|| isDefault
;
1197 * Clears the search engine popup.
1200 clearSearchEngines_: function() {
1201 $('default-search-engine').textContent
= '';
1205 * Updates the search engine popup with the given entries.
1206 * @param {Array} engines List of available search engines.
1207 * @param {number} defaultValue The value of the current default engine.
1208 * @param {boolean} defaultManaged Whether the default search provider is
1209 * managed. If true, the default search provider can't be changed.
1212 updateSearchEngines_: function(engines
, defaultValue
, defaultManaged
) {
1213 this.clearSearchEngines_();
1214 engineSelect
= $('default-search-engine');
1215 engineSelect
.disabled
= defaultManaged
;
1216 if (defaultManaged
&& defaultValue
== -1)
1218 engineCount
= engines
.length
;
1219 var defaultIndex
= -1;
1220 for (var i
= 0; i
< engineCount
; i
++) {
1221 var engine
= engines
[i
];
1222 var option
= new Option(engine
.name
, engine
.index
);
1223 if (defaultValue
== option
.value
)
1225 engineSelect
.appendChild(option
);
1227 if (defaultIndex
>= 0)
1228 engineSelect
.selectedIndex
= defaultIndex
;
1232 * Set the default search engine based on the popup selection.
1235 setDefaultSearchEngine_: function() {
1236 var engineSelect
= $('default-search-engine');
1237 var selectedIndex
= engineSelect
.selectedIndex
;
1238 if (selectedIndex
>= 0) {
1239 var selection
= engineSelect
.options
[selectedIndex
];
1240 chrome
.send('setDefaultSearchEngine', [String(selection
.value
)]);
1245 * Sets or clear whether Chrome should Auto-launch on computer startup.
1248 handleAutoLaunchChanged_: function() {
1249 chrome
.send('toggleAutoLaunch', [$('auto-launch').checked
]);
1253 * Get the selected profile item from the profile list. This also works
1254 * correctly if the list is not displayed.
1255 * @return {Object} the profile item object, or null if nothing is selected.
1258 getSelectedProfileItem_: function() {
1259 var profilesList
= $('profiles-list');
1260 if (profilesList
.hidden
) {
1261 if (profilesList
.dataModel
.length
> 0)
1262 return profilesList
.dataModel
.item(0);
1264 return profilesList
.selectedItem
;
1270 * Helper function to set the status of profile view buttons to disabled or
1271 * enabled, depending on the number of profiles and selection status of the
1275 setProfileViewButtonsStatus_: function() {
1276 var profilesList
= $('profiles-list');
1277 var selectedProfile
= profilesList
.selectedItem
;
1278 var hasSelection
= selectedProfile
!= null;
1279 var hasSingleProfile
= profilesList
.dataModel
.length
== 1;
1280 var isSupervised
= loadTimeData
.getBoolean('profileIsSupervised');
1281 $('profiles-manage').disabled
= !hasSelection
||
1282 !selectedProfile
.isCurrentProfile
;
1283 if (hasSelection
&& !selectedProfile
.isCurrentProfile
)
1284 $('profiles-manage').title
= loadTimeData
.getString('currentUserOnly');
1286 $('profiles-manage').title
= '';
1287 $('profiles-delete').disabled
= isSupervised
||
1288 (!hasSelection
&& !hasSingleProfile
);
1289 if (OptionsPage
.isSettingsApp()) {
1290 $('profiles-app-list-switch').disabled
= !hasSelection
||
1291 selectedProfile
.isCurrentProfile
;
1293 var importData
= $('import-data');
1295 importData
.disabled
= $('import-data').disabled
= hasSelection
&&
1296 !selectedProfile
.isCurrentProfile
;
1301 * Display the correct dialog layout, depending on how many profiles are
1303 * @param {number} numProfiles The number of profiles to display.
1306 setProfileViewSingle_: function(numProfiles
) {
1307 // Always show the profiles list when using the new Profiles UI.
1308 var usingNewProfilesUI
= loadTimeData
.getBoolean('usingNewProfilesUI');
1309 var showSingleProfileView
= !usingNewProfilesUI
&& numProfiles
== 1;
1310 $('profiles-list').hidden
= showSingleProfileView
;
1311 $('profiles-single-message').hidden
= !showSingleProfileView
;
1312 $('profiles-manage').hidden
=
1313 showSingleProfileView
|| OptionsPage
.isSettingsApp();
1314 $('profiles-delete').textContent
= showSingleProfileView
?
1315 loadTimeData
.getString('profilesDeleteSingle') :
1316 loadTimeData
.getString('profilesDelete');
1317 if (OptionsPage
.isSettingsApp())
1318 $('profiles-app-list-switch').hidden
= showSingleProfileView
;
1322 * Adds all |profiles| to the list.
1323 * @param {Array.<Object>} profiles An array of profile info objects.
1324 * each object is of the form:
1326 * name: "Profile Name",
1327 * iconURL: "chrome://path/to/icon/image",
1328 * filePath: "/path/to/profile/data/on/disk",
1329 * isCurrentProfile: false,
1330 * isSupervised: false
1334 setProfilesInfo_: function(profiles
) {
1335 this.setProfileViewSingle_(profiles
.length
);
1336 // add it to the list, even if the list is hidden so we can access it
1338 $('profiles-list').dataModel
= new ArrayDataModel(profiles
);
1340 // Received new data. If showing the "manage" overlay, keep it up to
1341 // date. If showing the "delete" overlay, close it.
1342 if (ManageProfileOverlay
.getInstance().visible
&&
1343 !$('manage-profile-overlay-manage').hidden
) {
1344 ManageProfileOverlay
.showManageDialog();
1346 ManageProfileOverlay
.getInstance().visible
= false;
1349 this.setProfileViewButtonsStatus_();
1353 * Reports supervised user import errors to the SupervisedUserImportOverlay.
1354 * @param {string} error The error message to display.
1357 showSupervisedUserImportError_: function(error
) {
1358 SupervisedUserImportOverlay
.onError(error
);
1362 * Reports successful importing of a supervised user to
1363 * the SupervisedUserImportOverlay.
1366 showSupervisedUserImportSuccess_: function() {
1367 SupervisedUserImportOverlay
.onSuccess();
1371 * Reports an error to the "create" overlay during profile creation.
1372 * @param {string} error The error message to display.
1375 showCreateProfileError_: function(error
) {
1376 CreateProfileOverlay
.onError(error
);
1380 * Sends a warning message to the "create" overlay during profile creation.
1381 * @param {string} warning The warning message to display.
1384 showCreateProfileWarning_: function(warning
) {
1385 CreateProfileOverlay
.onWarning(warning
);
1389 * Reports successful profile creation to the "create" overlay.
1390 * @param {Object} profileInfo An object of the form:
1392 * name: "Profile Name",
1393 * filePath: "/path/to/profile/data/on/disk"
1394 * isSupervised: (true|false),
1398 showCreateProfileSuccess_: function(profileInfo
) {
1399 CreateProfileOverlay
.onSuccess(profileInfo
);
1403 * Returns the currently active profile for this browser window.
1404 * @return {Object} A profile info object.
1407 getCurrentProfile_: function() {
1408 for (var i
= 0; i
< $('profiles-list').dataModel
.length
; i
++) {
1409 var profile
= $('profiles-list').dataModel
.item(i
);
1410 if (profile
.isCurrentProfile
)
1414 assertNotReached('There should always be a current profile.');
1418 * Propmpts user to confirm deletion of the profile for this browser
1422 deleteCurrentProfile_: function() {
1423 ManageProfileOverlay
.showDeleteDialog(this.getCurrentProfile_());
1427 * @param {boolean} enabled
1429 setNativeThemeButtonEnabled_: function(enabled
) {
1430 var button
= $('themes-native-button');
1432 button
.disabled
= !enabled
;
1436 * @param {boolean} enabled
1438 setThemesResetButtonEnabled_: function(enabled
) {
1439 $('themes-reset').disabled
= !enabled
;
1443 * @param {boolean} managed
1445 setAccountPictureManaged_: function(managed
) {
1446 var picture
= $('account-picture');
1447 if (managed
|| UIAccountTweaks
.loggedInAsGuest()) {
1448 picture
.disabled
= true;
1449 ChangePictureOptions
.closeOverlay();
1451 picture
.disabled
= false;
1454 // Create a synthetic pref change event decorated as
1455 // CoreOptionsHandler::CreateValueForPref() does.
1456 var event
= new Event('account-picture');
1458 event
.value
= { controlledBy
: 'policy' };
1461 $('account-picture-indicator').handlePrefChange(event
);
1465 * (Re)loads IMG element with current user account picture.
1468 updateAccountPicture_: function() {
1469 var picture
= $('account-picture');
1471 picture
.src
= 'chrome://userimage/' + this.username_
+ '?id=' +
1477 * @param {boolean} managed
1479 setWallpaperManaged_: function(managed
) {
1480 var button
= $('set-wallpaper');
1481 button
.disabled
= !!managed
;
1483 // Create a synthetic pref change event decorated as
1484 // CoreOptionsHandler::CreateValueForPref() does.
1485 var event
= new Event('wallpaper');
1487 event
.value
= { controlledBy
: 'policy' };
1490 $('wallpaper-indicator').handlePrefChange(event
);
1494 * Handle the 'add device' button click.
1497 handleAddBluetoothDevice_: function() {
1498 chrome
.send('findBluetoothDevices');
1499 PageManager
.showPageByName('bluetooth', false);
1503 * Enables or disables the Manage SSL Certificates button.
1506 enableCertificateButton_: function(enabled
) {
1507 $('certificatesManageButton').disabled
= !enabled
;
1511 * Enables factory reset section.
1514 enableFactoryResetSection_: function() {
1515 $('factory-reset-section').hidden
= false;
1519 * Set the checked state of the metrics reporting checkbox.
1522 setMetricsReportingCheckboxState_: function(checked
, disabled
) {
1523 $('metricsReportingEnabled').checked
= checked
;
1524 $('metricsReportingEnabled').disabled
= disabled
;
1526 // If checkbox gets disabled then add an attribute for displaying the
1527 // special icon. The opposite shouldn't be possible to do.
1529 $('metrics-reporting-disabled-icon').setAttribute('controlled-by',
1537 setMetricsReportingSettingVisibility_: function(visible
) {
1539 $('metricsReportingSetting').style
.display
= 'block';
1541 $('metricsReportingSetting').style
.display
= 'none';
1545 * Set network prediction checkbox value.
1547 * @param {{value: number, disabled: boolean}} pref Information about
1548 * network prediction options. |pref.value| is the value of network
1549 * prediction options. |pref.disabled| shows if the pref is not user
1553 setNetworkPredictionValue_: function(pref
) {
1554 var checkbox
= $('networkPredictionOptions');
1555 checkbox
.disabled
= pref
.disabled
;
1556 if (pref
.value
== NetworkPredictionOptions
.UNSET
) {
1557 checkbox
.checked
= (NetworkPredictionOptions
.DEFAULT
!=
1558 NetworkPredictionOptions
.NEVER
);
1560 checkbox
.checked
= (pref
.value
!= NetworkPredictionOptions
.NEVER
);
1565 * Set the font size selected item. This item actually reflects two
1566 * preferences: the default font size and the default fixed font size.
1568 * @param {{value: number, disabled: boolean, controlledBy: string}} pref
1569 * Information about the font size preferences. |pref.value| is the
1570 * value of the default font size pref. |pref.disabled| is true if
1571 * either pref not user modifiable. |pref.controlledBy| is the source of
1572 * the pref value(s) if either pref is currently not controlled by the
1576 setFontSize_: function(pref
) {
1577 var selectCtl
= $('defaultFontSize');
1578 selectCtl
.disabled
= pref
.disabled
;
1579 // Create a synthetic pref change event decorated as
1580 // CoreOptionsHandler::CreateValueForPref() does.
1581 var event
= new Event('synthetic-font-size');
1584 controlledBy
: pref
.controlledBy
,
1585 disabled
: pref
.disabled
1587 $('font-size-indicator').handlePrefChange(event
);
1589 for (var i
= 0; i
< selectCtl
.options
.length
; i
++) {
1590 if (selectCtl
.options
[i
].value
== pref
.value
) {
1591 selectCtl
.selectedIndex
= i
;
1593 selectCtl
.remove($('Custom').index
);
1598 // Add/Select Custom Option in the font size label list.
1600 var option
= new Option(loadTimeData
.getString('fontSizeLabelCustom'),
1602 option
.setAttribute('id', 'Custom');
1603 selectCtl
.add(option
);
1605 $('Custom').selected
= true;
1609 * Populate the page zoom selector with values received from the caller.
1610 * @param {Array} items An array of items to populate the selector.
1611 * each object is an array with three elements as follows:
1612 * 0: The title of the item (string).
1613 * 1: The value of the item (number).
1614 * 2: Whether the item should be selected (boolean).
1617 setupPageZoomSelector_: function(items
) {
1618 var element
= $('defaultZoomFactor');
1620 // Remove any existing content.
1621 element
.textContent
= '';
1623 // Insert new child nodes into select element.
1624 var value
, title
, selected
;
1625 for (var i
= 0; i
< items
.length
; i
++) {
1626 title
= items
[i
][0];
1627 value
= items
[i
][1];
1628 selected
= items
[i
][2];
1629 element
.appendChild(new Option(title
, value
, false, selected
));
1634 * Shows/hides the autoOpenFileTypesResetToDefault button and label, with
1636 * @param {boolean} display Whether to show the button and label or not.
1639 setAutoOpenFileTypesDisplayed_: function(display
) {
1640 if ($('advanced-settings').hidden
) {
1641 // If the Advanced section is hidden, don't animate the transition.
1642 $('auto-open-file-types-section').hidden
= !display
;
1645 this.showSectionWithAnimation_(
1646 $('auto-open-file-types-section'),
1647 $('auto-open-file-types-container'));
1649 this.hideSectionWithAnimation_(
1650 $('auto-open-file-types-section'),
1651 $('auto-open-file-types-container'));
1657 * Set the enabled state for the proxy settings button and its associated
1658 * message when extension controlled.
1659 * @param {boolean} disabled Whether the button should be disabled.
1660 * @param {boolean} extensionControlled Whether the proxy is extension
1664 setupProxySettingsButton_: function(disabled
, extensionControlled
) {
1665 if (!cr
.isChromeOS
) {
1666 $('proxiesConfigureButton').disabled
= disabled
;
1667 $('proxiesLabel').textContent
=
1668 loadTimeData
.getString(extensionControlled
?
1669 'proxiesLabelExtension' : 'proxiesLabelSystem');
1674 * Set the initial state of the spoken feedback checkbox.
1677 setSpokenFeedbackCheckboxState_: function(checked
) {
1678 $('accessibility-spoken-feedback-check').checked
= checked
;
1682 * Set the initial state of the high contrast checkbox.
1685 setHighContrastCheckboxState_: function(checked
) {
1686 $('accessibility-high-contrast-check').checked
= checked
;
1690 * Set the initial state of the virtual keyboard checkbox.
1693 setVirtualKeyboardCheckboxState_: function(checked
) {
1694 // TODO(zork): Update UI
1698 * Show/hide mouse settings slider.
1701 showMouseControls_: function(show
) {
1702 $('mouse-settings').hidden
= !show
;
1706 * Adds hidden warning boxes for settings potentially controlled by
1708 * @param {string} parentDiv The div name to append the bubble to.
1709 * @param {string} bubbleId The ID to use for the bubble.
1710 * @param {boolean} first Add as first node if true, otherwise last.
1713 addExtensionControlledBox_: function(parentDiv
, bubbleId
, first
) {
1714 var bubble
= $('extension-controlled-warning-template').cloneNode(true);
1715 bubble
.id
= bubbleId
;
1716 var parent
= $(parentDiv
);
1718 parent
.insertBefore(bubble
, parent
.firstChild
);
1720 parent
.appendChild(bubble
);
1724 * Adds a bubble showing that an extension is controlling a particular
1726 * @param {string} parentDiv The div name to append the bubble to.
1727 * @param {string} bubbleId The ID to use for the bubble.
1728 * @param {string} extensionId The ID of the controlling extension.
1729 * @param {string} extensionName The name of the controlling extension.
1732 toggleExtensionControlledBox_: function(
1733 parentDiv
, bubbleId
, extensionId
, extensionName
) {
1734 var bubble
= $(bubbleId
);
1736 bubble
.hidden
= extensionId
.length
== 0;
1740 // Set the extension image.
1741 var div
= bubble
.firstElementChild
;
1742 div
.style
.backgroundImage
=
1743 'url(chrome://extension-icon/' + extensionId
+ '/24/1)';
1745 // Set the bubble label.
1746 var label
= loadTimeData
.getStringF('extensionControlled', extensionName
);
1747 var docFrag
= parseHtmlSubset('<div>' + label
+ '</div>', ['B', 'DIV']);
1748 div
.innerHTML
= docFrag
.firstChild
.innerHTML
;
1750 // Wire up the button to disable the right extension.
1751 var button
= div
.nextElementSibling
;
1752 button
.dataset
.extensionId
= extensionId
;
1756 * Toggles the warning boxes that show which extension is controlling
1757 * various settings of Chrome.
1758 * @param {object} details A dictionary of ID+name pairs for each of the
1759 * settings controlled by an extension.
1762 toggleExtensionIndicators_: function(details
) {
1763 this.toggleExtensionControlledBox_('search-section-content',
1764 'search-engine-controlled',
1765 details
.searchEngine
.id
,
1766 details
.searchEngine
.name
);
1767 this.toggleExtensionControlledBox_('extension-controlled-container',
1768 'homepage-controlled',
1769 details
.homePage
.id
,
1770 details
.homePage
.name
);
1771 this.toggleExtensionControlledBox_('startup-section-content',
1772 'startpage-controlled',
1773 details
.startUpPage
.id
,
1774 details
.startUpPage
.name
);
1775 this.toggleExtensionControlledBox_('newtab-section-content',
1776 'newtab-controlled',
1777 details
.newTabPage
.id
,
1778 details
.newTabPage
.name
);
1779 this.toggleExtensionControlledBox_('proxy-section-content',
1782 details
.proxy
.name
);
1784 // The proxy section contains just the warning box and nothing else, so
1785 // if we're hiding the proxy warning box, we should also hide its header
1787 $('proxy-section').hidden
= details
.proxy
.id
.length
== 0;
1792 * Show/hide touchpad-related settings.
1795 showTouchpadControls_: function(show
) {
1796 $('touchpad-settings').hidden
= !show
;
1797 $('accessibility-tap-dragging').hidden
= !show
;
1801 * Activate the Bluetooth settings section on the System settings page.
1804 showBluetoothSettings_: function() {
1805 $('bluetooth-devices').hidden
= false;
1809 * Dectivates the Bluetooth settings section from the System settings page.
1812 hideBluetoothSettings_: function() {
1813 $('bluetooth-devices').hidden
= true;
1817 * Sets the state of the checkbox indicating if Bluetooth is turned on. The
1818 * state of the "Find devices" button and the list of discovered devices may
1819 * also be affected by a change to the state.
1820 * @param {boolean} checked Flag Indicating if Bluetooth is turned on.
1823 setBluetoothState_: function(checked
) {
1824 $('enable-bluetooth').checked
= checked
;
1825 $('bluetooth-paired-devices-list').parentNode
.hidden
= !checked
;
1826 $('bluetooth-add-device').hidden
= !checked
;
1827 $('bluetooth-reconnect-device').hidden
= !checked
;
1828 // Flush list of previously discovered devices if bluetooth is turned off.
1830 $('bluetooth-paired-devices-list').clear();
1831 $('bluetooth-unpaired-devices-list').clear();
1833 chrome
.send('getPairedBluetoothDevices');
1838 * Adds an element to the list of available Bluetooth devices. If an element
1839 * with a matching address is found, the existing element is updated.
1840 * @param {{name: string,
1843 * connected: boolean}} device
1844 * Decription of the Bluetooth device.
1847 addBluetoothDevice_: function(device
) {
1848 var list
= $('bluetooth-unpaired-devices-list');
1849 // Display the "connecting" (already paired or not yet paired) and the
1850 // paired devices in the same list.
1851 if (device
.paired
|| device
.connecting
) {
1852 // Test to see if the device is currently in the unpaired list, in which
1853 // case it should be removed from that list.
1854 var index
= $('bluetooth-unpaired-devices-list').find(device
.address
);
1855 if (index
!= undefined)
1856 $('bluetooth-unpaired-devices-list').deleteItemAtIndex(index
);
1857 list
= $('bluetooth-paired-devices-list');
1859 // Test to see if the device is currently in the paired list, in which
1860 // case it should be removed from that list.
1861 var index
= $('bluetooth-paired-devices-list').find(device
.address
);
1862 if (index
!= undefined)
1863 $('bluetooth-paired-devices-list').deleteItemAtIndex(index
);
1865 list
.appendDevice(device
);
1867 // One device can be in the process of pairing. If found, display
1868 // the Bluetooth pairing overlay.
1870 BluetoothPairing
.showDialog(device
);
1874 * Removes an element from the list of available devices.
1875 * @param {string} address Unique address of the device.
1878 removeBluetoothDevice_: function(address
) {
1879 var index
= $('bluetooth-unpaired-devices-list').find(address
);
1880 if (index
!= undefined) {
1881 $('bluetooth-unpaired-devices-list').deleteItemAtIndex(index
);
1883 index
= $('bluetooth-paired-devices-list').find(address
);
1884 if (index
!= undefined)
1885 $('bluetooth-paired-devices-list').deleteItemAtIndex(index
);
1890 * Shows the overlay dialog for changing the user avatar image.
1893 showImagerPickerOverlay_: function() {
1894 PageManager
.showPageByName('changePicture');
1898 * Shows (or not) the "User" section of the settings page based on whether
1899 * any of the sub-sections are present (or not).
1902 maybeShowUserSection_: function() {
1903 $('sync-users-section').hidden
=
1904 $('profiles-section').hidden
&&
1905 $('sync-section').hidden
&&
1906 $('profiles-supervised-dashboard-tip').hidden
;
1910 * Updates the date and time section with time sync information.
1911 * @param {boolean} canSetTime Whether the system time can be set.
1914 setCanSetTime_: function(canSetTime
) {
1915 // If the time has been network-synced, it cannot be set manually.
1916 $('time-synced-explanation').hidden
= canSetTime
;
1917 $('set-time').hidden
= !canSetTime
;
1921 * Handle the 'set date and time' button click.
1924 handleSetTime_: function() {
1925 chrome
.send('showSetTime');
1929 //Forward public APIs to private implementations.
1930 cr
.makePublic(BrowserOptions
, [
1931 'addBluetoothDevice',
1932 'deleteCurrentProfile',
1933 'enableCertificateButton',
1934 'enableFactoryResetSection',
1935 'getCurrentProfile',
1936 'getStartStopSyncButton',
1937 'hideBluetoothSettings',
1938 'notifyInitializationComplete',
1939 'removeBluetoothDevice',
1941 'setAccountPictureManaged',
1942 'setWallpaperManaged',
1943 'setAutoOpenFileTypesDisplayed',
1944 'setBluetoothState',
1947 'setNativeThemeButtonEnabled',
1948 'setNetworkPredictionValue',
1949 'setHighContrastCheckboxState',
1950 'setMetricsReportingCheckboxState',
1951 'setMetricsReportingSettingVisibility',
1953 'setSpokenFeedbackCheckboxState',
1954 'setThemesResetButtonEnabled',
1955 'setVirtualKeyboardCheckboxState',
1956 'setupPageZoomSelector',
1957 'setupProxySettingsButton',
1958 'showBluetoothSettings',
1959 'showCreateProfileError',
1960 'showCreateProfileSuccess',
1961 'showCreateProfileWarning',
1962 'showHotwordAlwaysOnSection',
1963 'showHotwordSection',
1964 'showMouseControls',
1965 'showSupervisedUserImportError',
1966 'showSupervisedUserImportSuccess',
1967 'showTouchpadControls',
1968 'toggleExtensionIndicators',
1969 'updateAccountPicture',
1970 'updateAutoLaunchState',
1971 'updateDefaultBrowserState',
1973 'updateManagesSupervisedUsers',
1974 'updateSearchEngines',
1978 if (cr
.isChromeOS
) {
1980 * Returns username (canonical email) of the user logged in (ChromeOS only).
1981 * @return {string} user email.
1983 // TODO(jhawkins): Investigate the use case for this method.
1984 BrowserOptions
.getLoggedInUsername = function() {
1985 return BrowserOptions
.getInstance().username_
;
1989 * Shows different button text for each consumer management enrollment
1991 * @enum {string} status Consumer management service status string.
1993 BrowserOptions
.setConsumerManagementStatus = function(status
) {
1994 var button
= $('consumer-management-button');
1995 if (status
== 'StatusUnknown') {
1996 button
.hidden
= true;
2000 button
.hidden
= false;
2003 case ConsumerManagementOverlay
.Status
.STATUS_UNENROLLED
:
2004 strId
= 'consumerManagementEnrollButton';
2005 button
.disabled
= false;
2006 ConsumerManagementOverlay
.setStatus(status
);
2008 case ConsumerManagementOverlay
.Status
.STATUS_ENROLLING
:
2009 strId
= 'consumerManagementEnrollingButton';
2010 button
.disabled
= true;
2012 case ConsumerManagementOverlay
.Status
.STATUS_ENROLLED
:
2013 strId
= 'consumerManagementUnenrollButton';
2014 button
.disabled
= false;
2015 ConsumerManagementOverlay
.setStatus(status
);
2017 case ConsumerManagementOverlay
.Status
.STATUS_UNENROLLING
:
2018 strId
= 'consumerManagementUnenrollingButton';
2019 button
.disabled
= true;
2022 button
.textContent
= loadTimeData
.getString(strId
);
2028 BrowserOptions
: BrowserOptions