1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5cr.exportPath('options');
6
7/**
8 * @typedef {{actionLinkText: (string|undefined),
9 *            hasError: (boolean|undefined),
10 *            hasUnrecoverableError: (boolean|undefined),
11 *            managed: (boolean|undefined),
12 *            setupCompleted: (boolean|undefined),
13 *            setupInProgress: (boolean|undefined),
14 *            signedIn: (boolean|undefined),
15 *            signinAllowed: (boolean|undefined),
16 *            signinAllowed: boolean,
17 *            signoutAllowed: (boolean|undefined),
18 *            statusText: (string|undefined),
19 *            syncSystemEnabled: (boolean|undefined)}}
20 * @see chrome/browser/ui/webui/options/browser_options_handler.cc
21 */
22options.SyncStatus;
23
24cr.define('options', function() {
25  var OptionsPage = options.OptionsPage;
26  var Page = cr.ui.pageManager.Page;
27  var PageManager = cr.ui.pageManager.PageManager;
28  var ArrayDataModel = cr.ui.ArrayDataModel;
29  var RepeatingButton = cr.ui.RepeatingButton;
30  var HotwordSearchSettingIndicator = options.HotwordSearchSettingIndicator;
31  var NetworkPredictionOptions = {
32    ALWAYS: 0,
33    WIFI_ONLY: 1,
34    NEVER: 2,
35    UNSET: 3,
36    DEFAULT: 1
37  };
38
39  /**
40   * Encapsulated handling of browser options page.
41   * @constructor
42   * @extends {cr.ui.pageManager.Page}
43   */
44  function BrowserOptions() {
45    Page.call(this, 'settings', loadTimeData.getString('settingsTitle'),
46              'settings');
47  }
48
49  cr.addSingletonGetter(BrowserOptions);
50
51  /**
52   * @param {HTMLElement} section The section to show or hide.
53   * @return {boolean} Whether the section should be shown.
54   * @private
55   */
56  BrowserOptions.shouldShowSection_ = function(section) {
57    // If the section is hidden or hiding, it should be shown.
58    return section.style.height == '' || section.style.height == '0px';
59  };
60
61  BrowserOptions.prototype = {
62    __proto__: Page.prototype,
63
64    /**
65     * Keeps track of whether the user is signed in or not.
66     * @type {boolean}
67     * @private
68     */
69    signedIn_: false,
70
71    /**
72     * Indicates whether signing out is allowed or whether a complete profile
73     * wipe is required to remove the current enterprise account.
74     * @type {boolean}
75     * @private
76     */
77    signoutAllowed_: true,
78
79    /**
80     * Keeps track of whether |onShowHomeButtonChanged_| has been called. See
81     * |onShowHomeButtonChanged_|.
82     * @type {boolean}
83     * @private
84     */
85    onShowHomeButtonChangedCalled_: false,
86
87    /**
88     * Track if page initialization is complete.  All C++ UI handlers have the
89     * chance to manipulate page content within their InitializePage methods.
90     * This flag is set to true after all initializers have been called.
91     * @type {boolean}
92     * @private
93     */
94    initializationComplete_: false,
95
96    /** @override */
97    initializePage: function() {
98      Page.prototype.initializePage.call(this);
99      var self = this;
100
101      if (window.top != window) {
102        // The options page is not in its own window.
103        document.body.classList.add('uber-frame');
104        PageManager.horizontalOffset = 155;
105      }
106
107      // Ensure that navigation events are unblocked on uber page. A reload of
108      // the settings page while an overlay is open would otherwise leave uber
109      // page in a blocked state, where tab switching is not possible.
110      uber.invokeMethodOnParent('stopInterceptingEvents');
111
112      window.addEventListener('message', this.handleWindowMessage_.bind(this));
113
114      if (loadTimeData.getBoolean('allowAdvancedSettings')) {
115        $('advanced-settings-expander').onclick = function() {
116          var showAdvanced =
117              BrowserOptions.shouldShowSection_($('advanced-settings'));
118          if (showAdvanced) {
119            chrome.send('coreOptionsUserMetricsAction',
120                        ['Options_ShowAdvancedSettings']);
121          }
122          self.toggleSectionWithAnimation_(
123              $('advanced-settings'),
124              $('advanced-settings-container'));
125
126          // If the link was focused (i.e., it was activated using the keyboard)
127          // and it was used to show the section (rather than hiding it), focus
128          // the first element in the container.
129          if (document.activeElement === $('advanced-settings-expander') &&
130              showAdvanced) {
131            var focusElement = $('advanced-settings-container').querySelector(
132                'button, input, list, select, a[href]');
133            if (focusElement)
134              focusElement.focus();
135          }
136        };
137      } else {
138        $('advanced-settings-expander').hidden = true;
139        $('advanced-settings').hidden = true;
140      }
141
142      $('advanced-settings').addEventListener('webkitTransitionEnd',
143          this.updateAdvancedSettingsExpander_.bind(this));
144
145      if (loadTimeData.getBoolean('showAbout')) {
146        $('about-button').hidden = false;
147        $('about-button').addEventListener('click', function() {
148          PageManager.showPageByName('help');
149          chrome.send('coreOptionsUserMetricsAction',
150                      ['Options_About']);
151        });
152      }
153
154      if (cr.isChromeOS) {
155        UIAccountTweaks.applyGuestSessionVisibility(document);
156        UIAccountTweaks.applyPublicSessionVisibility(document);
157        if (loadTimeData.getBoolean('secondaryUser'))
158          $('secondary-user-banner').hidden = false;
159      }
160
161      // Sync (Sign in) section.
162      this.updateSyncState_(loadTimeData.getValue('syncData'));
163
164      $('start-stop-sync').onclick = function(event) {
165        if (self.signedIn_) {
166          if (self.signoutAllowed_)
167            SyncSetupOverlay.showStopSyncingUI();
168          else
169            chrome.send('showDisconnectManagedProfileDialog');
170        } else if (cr.isChromeOS) {
171          SyncSetupOverlay.showSetupUI();
172        } else {
173          SyncSetupOverlay.startSignIn();
174        }
175      };
176      $('customize-sync').onclick = function(event) {
177        SyncSetupOverlay.showSetupUI();
178      };
179
180      // Internet connection section (ChromeOS only).
181      if (cr.isChromeOS) {
182        options.network.NetworkList.decorate($('network-list'));
183        // Show that the network settings are shared if this is a secondary user
184        // in a multi-profile session.
185        if (loadTimeData.getBoolean('secondaryUser')) {
186          var networkIndicator = document.querySelector(
187              '#network-section-header > .controlled-setting-indicator');
188          networkIndicator.setAttribute('controlled-by', 'shared');
189          networkIndicator.location = cr.ui.ArrowLocation.TOP_START;
190        }
191        options.network.NetworkList.refreshNetworkData(
192            loadTimeData.getValue('networkData'));
193      }
194
195      // On Startup section.
196      Preferences.getInstance().addEventListener('session.restore_on_startup',
197          this.onRestoreOnStartupChanged_.bind(this));
198      Preferences.getInstance().addEventListener(
199          'session.startup_urls',
200          function(event) {
201            $('startup-set-pages').disabled = event.value.disabled;
202          });
203
204      $('startup-set-pages').onclick = function() {
205        PageManager.showPageByName('startup');
206      };
207
208      // Appearance section.
209      Preferences.getInstance().addEventListener('browser.show_home_button',
210          this.onShowHomeButtonChanged_.bind(this));
211
212      Preferences.getInstance().addEventListener('homepage',
213          this.onHomePageChanged_.bind(this));
214      Preferences.getInstance().addEventListener('homepage_is_newtabpage',
215          this.onHomePageIsNtpChanged_.bind(this));
216
217      $('change-home-page').onclick = function(event) {
218        PageManager.showPageByName('homePageOverlay');
219        chrome.send('coreOptionsUserMetricsAction',
220                    ['Options_Homepage_ShowSettings']);
221      };
222
223      var hotwordIndicator = $('hotword-search-setting-indicator');
224      HotwordSearchSettingIndicator.decorate(hotwordIndicator);
225      chrome.send('requestHotwordAvailable');
226
227      if ($('set-wallpaper')) {
228        $('set-wallpaper').onclick = function(event) {
229          chrome.send('openWallpaperManager');
230          chrome.send('coreOptionsUserMetricsAction',
231                      ['Options_OpenWallpaperManager']);
232        };
233      }
234
235      // Control the hotword-always-on pref with the Hotword Audio
236      // Verification app.
237      $('hotword-always-on-search-checkbox').customChangeHandler =
238          function(event) {
239        if (!$('hotword-always-on-search-checkbox').checked)
240          return false;
241
242        $('hotword-always-on-search-checkbox').checked = false;
243        chrome.send('launchHotwordAudioVerificationApp', [false]);
244        return true;
245      };
246
247      $('themes-gallery').onclick = function(event) {
248        window.open(loadTimeData.getString('themesGalleryURL'));
249        chrome.send('coreOptionsUserMetricsAction',
250                    ['Options_ThemesGallery']);
251      };
252      $('themes-reset').onclick = function(event) {
253        chrome.send('themesReset');
254      };
255
256      if (loadTimeData.getBoolean('profileIsSupervised')) {
257        if ($('themes-native-button')) {
258          $('themes-native-button').disabled = true;
259          $('themes-native-button').hidden = true;
260        }
261        // Supervised users have just one default theme, even on Linux. So use
262        // the same button for Linux as for the other platforms.
263        $('themes-reset').textContent = loadTimeData.getString('themesReset');
264      }
265
266      // Device section (ChromeOS only).
267      if (cr.isChromeOS) {
268        $('battery-button').onclick = function(evt) {
269          WebsiteSettingsManager.showWebsiteSettings('battery');
270        };
271        $('stored-data-button').onclick = function(evt) {
272          WebsiteSettingsManager.showWebsiteSettings('storage');
273        };
274        $('keyboard-settings-button').onclick = function(evt) {
275          PageManager.showPageByName('keyboard-overlay');
276          chrome.send('coreOptionsUserMetricsAction',
277                      ['Options_ShowKeyboardSettings']);
278        };
279        $('pointer-settings-button').onclick = function(evt) {
280          PageManager.showPageByName('pointer-overlay');
281          chrome.send('coreOptionsUserMetricsAction',
282                      ['Options_ShowTouchpadSettings']);
283        };
284      }
285
286      // Search section.
287      $('manage-default-search-engines').onclick = function(event) {
288        PageManager.showPageByName('searchEngines');
289        chrome.send('coreOptionsUserMetricsAction',
290                    ['Options_ManageSearchEngines']);
291      };
292      $('default-search-engine').addEventListener('change',
293          this.setDefaultSearchEngine_);
294
295      // Users section.
296      if (loadTimeData.valueExists('profilesInfo')) {
297        $('profiles-section').hidden = false;
298        this.maybeShowUserSection_();
299
300        var profilesList = $('profiles-list');
301        options.browser_options.ProfileList.decorate(profilesList);
302        profilesList.autoExpands = true;
303
304        // The profiles info data in |loadTimeData| might be stale.
305        this.setProfilesInfo_(loadTimeData.getValue('profilesInfo'));
306        chrome.send('requestProfilesInfo');
307
308        profilesList.addEventListener('change',
309            this.setProfileViewButtonsStatus_);
310        $('profiles-create').onclick = function(event) {
311          ManageProfileOverlay.showCreateDialog();
312        };
313        if (OptionsPage.isSettingsApp()) {
314          $('profiles-app-list-switch').onclick = function(event) {
315            var selectedProfile = self.getSelectedProfileItem_();
316            chrome.send('switchAppListProfile', [selectedProfile.filePath]);
317          };
318        }
319        $('profiles-manage').onclick = function(event) {
320          ManageProfileOverlay.showManageDialog();
321        };
322        $('profiles-delete').onclick = function(event) {
323          var selectedProfile = self.getSelectedProfileItem_();
324          if (selectedProfile)
325            ManageProfileOverlay.showDeleteDialog(selectedProfile);
326        };
327        if (loadTimeData.getBoolean('profileIsSupervised')) {
328          $('profiles-create').disabled = true;
329          $('profiles-delete').disabled = true;
330          $('profiles-list').canDeleteItems = false;
331        }
332      }
333
334      if (cr.isChromeOS) {
335        // Username (canonical email) of the currently logged in user or
336        // |kGuestUser| if a guest session is active.
337        this.username_ = loadTimeData.getString('username');
338
339        this.updateAccountPicture_();
340
341        $('account-picture').onclick = this.showImagerPickerOverlay_;
342        $('change-picture-caption').onclick = this.showImagerPickerOverlay_;
343
344        $('manage-accounts-button').onclick = function(event) {
345          PageManager.showPageByName('accounts');
346          chrome.send('coreOptionsUserMetricsAction',
347              ['Options_ManageAccounts']);
348        };
349      } else {
350        $('import-data').onclick = function(event) {
351          ImportDataOverlay.show();
352          chrome.send('coreOptionsUserMetricsAction', ['Import_ShowDlg']);
353        };
354
355        if ($('themes-native-button')) {
356          $('themes-native-button').onclick = function(event) {
357            chrome.send('themesSetNative');
358          };
359        }
360      }
361
362      // Date and time section (CrOS only).
363      if ($('set-time-button'))
364        $('set-time-button').onclick = this.handleSetTime_.bind(this);
365
366      // Default browser section.
367      if (!cr.isChromeOS) {
368        if (!loadTimeData.getBoolean('showSetDefault')) {
369          $('set-default-browser-section').hidden = true;
370        }
371        $('set-as-default-browser').onclick = function(event) {
372          chrome.send('becomeDefaultBrowser');
373        };
374
375        $('auto-launch').onclick = this.handleAutoLaunchChanged_;
376      }
377
378      // Privacy section.
379      $('privacyContentSettingsButton').onclick = function(event) {
380        PageManager.showPageByName('content');
381        OptionsPage.showTab($('cookies-nav-tab'));
382        chrome.send('coreOptionsUserMetricsAction',
383            ['Options_ContentSettings']);
384      };
385      $('privacyClearDataButton').onclick = function(event) {
386        PageManager.showPageByName('clearBrowserData');
387        chrome.send('coreOptionsUserMetricsAction', ['Options_ClearData']);
388      };
389      $('privacyClearDataButton').hidden = OptionsPage.isSettingsApp();
390      // 'metricsReportingEnabled' element is only present on Chrome branded
391      // builds, and the 'metricsReportingCheckboxAction' message is only
392      // handled on ChromeOS.
393      if ($('metricsReportingEnabled') && cr.isChromeOS) {
394        $('metricsReportingEnabled').onclick = function(event) {
395          chrome.send('metricsReportingCheckboxAction',
396              [String(event.currentTarget.checked)]);
397        };
398      }
399      if ($('metricsReportingEnabled') && !cr.isChromeOS) {
400        // The localized string has the | symbol on each side of the text that
401        // needs to be made into a button to restart Chrome. We parse the text
402        // and build the button from that.
403        var restartTextFragments =
404            loadTimeData.getString('metricsReportingResetRestart').split('|');
405        // Assume structure is something like "starting text |link text| ending
406        // text" where both starting text and ending text may or may not be
407        // present, but the split should always be in three pieces.
408        var restartElements =
409            $('metrics-reporting-reset-restart').querySelectorAll('*');
410        for (var i = 0; i < restartTextFragments.length; i++) {
411          restartElements[i].textContent = restartTextFragments[i];
412        }
413        restartElements[1].onclick = function(event) {
414          chrome.send('restartBrowser');
415        };
416        // Attach the listener for updating the checkbox and restart button.
417        var updateMetricsRestartButton = function() {
418          $('metrics-reporting-reset-restart').hidden =
419              loadTimeData.getBoolean('metricsReportingEnabledAtStart') ==
420                  $('metricsReportingEnabled').checked;
421        };
422        $('metricsReportingEnabled').onclick = function(event) {
423          chrome.send('metricsReportingCheckboxChanged',
424              [Boolean(event.currentTarget.checked)]);
425          updateMetricsRestartButton();
426        };
427        $('metricsReportingEnabled').checked =
428            loadTimeData.getBoolean('metricsReportingEnabledAtStart');
429        updateMetricsRestartButton();
430      }
431      $('networkPredictionOptions').onchange = function(event) {
432        var value = (event.target.checked ?
433            NetworkPredictionOptions.WIFI_ONLY :
434            NetworkPredictionOptions.NEVER);
435        var metric = event.target.metric;
436        Preferences.setIntegerPref(
437            'net.network_prediction_options',
438            value,
439            true,
440            metric);
441      };
442
443      // Bluetooth (CrOS only).
444      if (cr.isChromeOS) {
445        options.system.bluetooth.BluetoothDeviceList.decorate(
446            $('bluetooth-paired-devices-list'));
447
448        $('bluetooth-add-device').onclick =
449            this.handleAddBluetoothDevice_.bind(this);
450
451        $('enable-bluetooth').onchange = function(event) {
452          var state = $('enable-bluetooth').checked;
453          chrome.send('bluetoothEnableChange', [Boolean(state)]);
454        };
455
456        $('bluetooth-reconnect-device').onclick = function(event) {
457          var device = $('bluetooth-paired-devices-list').selectedItem;
458          var address = device.address;
459          chrome.send('updateBluetoothDevice', [address, 'connect']);
460          PageManager.closeOverlay();
461        };
462
463        $('bluetooth-paired-devices-list').addEventListener('change',
464            function() {
465          var item = $('bluetooth-paired-devices-list').selectedItem;
466          var disabled = !item || item.connected || !item.connectable;
467          $('bluetooth-reconnect-device').disabled = disabled;
468        });
469      }
470
471      // Passwords and Forms section.
472      $('autofill-settings').onclick = function(event) {
473        PageManager.showPageByName('autofill');
474        chrome.send('coreOptionsUserMetricsAction',
475            ['Options_ShowAutofillSettings']);
476      };
477      $('manage-passwords').onclick = function(event) {
478        PageManager.showPageByName('passwords');
479        OptionsPage.showTab($('passwords-nav-tab'));
480        chrome.send('coreOptionsUserMetricsAction',
481            ['Options_ShowPasswordManager']);
482      };
483      if (cr.isChromeOS && UIAccountTweaks.loggedInAsGuest()) {
484        // Disable and turn off Autofill in guest mode.
485        var autofillEnabled = $('autofill-enabled');
486        autofillEnabled.disabled = true;
487        autofillEnabled.checked = false;
488        cr.dispatchSimpleEvent(autofillEnabled, 'change');
489        $('autofill-settings').disabled = true;
490
491        // Disable and turn off Password Manager in guest mode.
492        var passwordManagerEnabled = $('password-manager-enabled');
493        passwordManagerEnabled.disabled = true;
494        passwordManagerEnabled.checked = false;
495        cr.dispatchSimpleEvent(passwordManagerEnabled, 'change');
496        $('manage-passwords').disabled = true;
497      }
498
499      if (cr.isMac) {
500        $('mac-passwords-warning').hidden =
501            !loadTimeData.getBoolean('multiple_profiles');
502      }
503
504      // Network section.
505      if (!cr.isChromeOS) {
506        $('proxiesConfigureButton').onclick = function(event) {
507          chrome.send('showNetworkProxySettings');
508        };
509      }
510
511      // Device control section.
512      if (cr.isChromeOS &&
513          UIAccountTweaks.currentUserIsOwner() &&
514          loadTimeData.getBoolean('consumerManagementEnabled')) {
515        $('device-control-section').hidden = false;
516        $('consumer-management-button').onclick = function(event) {
517          PageManager.showPageByName('consumer-management-overlay');
518        };
519      }
520
521      // Easy Unlock section.
522      if (loadTimeData.getBoolean('easyUnlockAllowed')) {
523        $('easy-unlock-section').hidden = false;
524        $('easy-unlock-setup-button').onclick = function(event) {
525          chrome.send('launchEasyUnlockSetup');
526        };
527        $('easy-unlock-turn-off-button').onclick = function(event) {
528          PageManager.showPageByName('easyUnlockTurnOffOverlay');
529        };
530      }
531
532      // Website Settings section.
533      if (loadTimeData.getBoolean('websiteSettingsManagerEnabled')) {
534        $('website-settings-section').hidden = false;
535        $('website-management-button').onclick = function(event) {
536          PageManager.showPageByName('websiteSettings');
537        };
538      }
539
540      // Web Content section.
541      $('fontSettingsCustomizeFontsButton').onclick = function(event) {
542        PageManager.showPageByName('fonts');
543        chrome.send('coreOptionsUserMetricsAction', ['Options_FontSettings']);
544      };
545      $('defaultFontSize').onchange = function(event) {
546        var value = event.target.options[event.target.selectedIndex].value;
547        Preferences.setIntegerPref(
548             'webkit.webprefs.default_fixed_font_size',
549             value - OptionsPage.SIZE_DIFFERENCE_FIXED_STANDARD, true);
550        chrome.send('defaultFontSizeAction', [String(value)]);
551      };
552      $('defaultZoomFactor').onchange = function(event) {
553        chrome.send('defaultZoomFactorAction',
554            [String(event.target.options[event.target.selectedIndex].value)]);
555      };
556
557      // Languages section.
558      var showLanguageOptions = function(event) {
559        PageManager.showPageByName('languages');
560        chrome.send('coreOptionsUserMetricsAction',
561            ['Options_LanuageAndSpellCheckSettings']);
562      };
563      $('language-button').onclick = showLanguageOptions;
564      $('manage-languages').onclick = showLanguageOptions;
565
566      // Downloads section.
567      Preferences.getInstance().addEventListener('download.default_directory',
568          this.onDefaultDownloadDirectoryChanged_.bind(this));
569      $('downloadLocationChangeButton').onclick = function(event) {
570        chrome.send('selectDownloadLocation');
571      };
572      if (cr.isChromeOS) {
573        $('disable-drive-row').hidden =
574            UIAccountTweaks.loggedInAsSupervisedUser();
575      }
576      $('autoOpenFileTypesResetToDefault').onclick = function(event) {
577        chrome.send('autoOpenFileTypesAction');
578      };
579
580      // HTTPS/SSL section.
581      if (cr.isWindows || cr.isMac) {
582        $('certificatesManageButton').onclick = function(event) {
583          chrome.send('showManageSSLCertificates');
584        };
585      } else {
586        $('certificatesManageButton').onclick = function(event) {
587          PageManager.showPageByName('certificates');
588          chrome.send('coreOptionsUserMetricsAction',
589                      ['Options_ManageSSLCertificates']);
590        };
591      }
592
593      if (loadTimeData.getBoolean('cloudPrintShowMDnsOptions')) {
594        $('cloudprint-options-mdns').hidden = false;
595        $('cloudPrintDevicesPageButton').onclick = function() {
596          chrome.send('showCloudPrintDevicesPage');
597        };
598      }
599
600      // Accessibility section (CrOS only).
601      if (cr.isChromeOS) {
602        var updateAccessibilitySettingsButton = function() {
603          $('accessibility-settings').hidden =
604              !($('accessibility-spoken-feedback-check').checked);
605        };
606        Preferences.getInstance().addEventListener(
607            'settings.accessibility',
608            updateAccessibilitySettingsButton);
609        $('accessibility-learn-more').onclick = function(unused_event) {
610          window.open(loadTimeData.getString('accessibilityLearnMoreURL'));
611          chrome.send('coreOptionsUserMetricsAction',
612                      ['Options_AccessibilityLearnMore']);
613        };
614        $('accessibility-settings-button').onclick = function(unused_event) {
615          window.open(loadTimeData.getString('accessibilitySettingsURL'));
616        };
617        $('accessibility-spoken-feedback-check').onchange = function(
618            unused_event) {
619          chrome.send('spokenFeedbackChange',
620                      [$('accessibility-spoken-feedback-check').checked]);
621          updateAccessibilitySettingsButton();
622        };
623        updateAccessibilitySettingsButton();
624
625        $('accessibility-high-contrast-check').onchange = function(
626            unused_event) {
627          chrome.send('highContrastChange',
628                      [$('accessibility-high-contrast-check').checked]);
629        };
630
631        var updateDelayDropdown = function() {
632          $('accessibility-autoclick-dropdown').disabled =
633              !$('accessibility-autoclick-check').checked;
634        };
635        Preferences.getInstance().addEventListener(
636            $('accessibility-autoclick-check').getAttribute('pref'),
637            updateDelayDropdown);
638      }
639
640      // Display management section (CrOS only).
641      if (cr.isChromeOS) {
642        $('display-options').onclick = function(event) {
643          PageManager.showPageByName('display');
644          chrome.send('coreOptionsUserMetricsAction',
645                      ['Options_Display']);
646        };
647      }
648
649      // Factory reset section (CrOS only).
650      if (cr.isChromeOS) {
651        $('factory-reset-restart').onclick = function(event) {
652          PageManager.showPageByName('factoryResetData');
653          chrome.send('onPowerwashDialogShow');
654        };
655      }
656
657      // System section.
658      if (!cr.isChromeOS) {
659        var updateGpuRestartButton = function() {
660          $('gpu-mode-reset-restart').hidden =
661              loadTimeData.getBoolean('gpuEnabledAtStart') ==
662              $('gpu-mode-checkbox').checked;
663        };
664        Preferences.getInstance().addEventListener(
665            $('gpu-mode-checkbox').getAttribute('pref'),
666            updateGpuRestartButton);
667        $('gpu-mode-reset-restart-button').onclick = function(event) {
668          chrome.send('restartBrowser');
669        };
670        updateGpuRestartButton();
671      }
672
673      // Reset profile settings section.
674      $('reset-profile-settings').onclick = function(event) {
675        PageManager.showPageByName('resetProfileSettings');
676      };
677
678      // Extension controlled UI.
679      this.addExtensionControlledBox_('search-section-content',
680                                      'search-engine-controlled',
681                                      true);
682      this.addExtensionControlledBox_('extension-controlled-container',
683                                      'homepage-controlled',
684                                      true);
685      this.addExtensionControlledBox_('startup-section-content',
686                                      'startpage-controlled',
687                                      false);
688      this.addExtensionControlledBox_('newtab-section-content',
689                                      'newtab-controlled',
690                                      false);
691      this.addExtensionControlledBox_('proxy-section-content',
692                                      'proxy-controlled',
693                                      true);
694
695      document.body.addEventListener('click', function(e) {
696        var target = assertInstanceof(e.target, Node);
697        var button = findAncestor(target, function(el) {
698          return el.tagName == 'BUTTON' &&
699                 el.dataset.extensionId !== undefined &&
700                 el.dataset.extensionId.length;
701        });
702        if (button)
703          chrome.send('disableExtension', [button.dataset.extensionId]);
704      });
705    },
706
707    /** @override */
708    didShowPage: function() {
709      $('search-field').focus();
710    },
711
712   /**
713    * Called after all C++ UI handlers have called InitializePage to notify
714    * that initialization is complete.
715    * @private
716    */
717    notifyInitializationComplete_: function() {
718      this.initializationComplete_ = true;
719      cr.dispatchSimpleEvent(document, 'initializationComplete');
720    },
721
722    /**
723     * Event listener for the 'session.restore_on_startup' pref.
724     * @param {Event} event The preference change event.
725     * @private
726     */
727    onRestoreOnStartupChanged_: function(event) {
728      /** @const */ var showHomePageValue = 0;
729
730      if (event.value.value == showHomePageValue) {
731        // If the user previously selected "Show the homepage", the
732        // preference will already be migrated to "Open a specific page". So
733        // the only way to reach this code is if the 'restore on startup'
734        // preference is managed.
735        assert(event.value.controlledBy);
736
737        // Select "open the following pages" and lock down the list of URLs
738        // to reflect the intention of the policy.
739        $('startup-show-pages').checked = true;
740        StartupOverlay.getInstance().setControlsDisabled(true);
741      } else {
742        // Re-enable the controls in the startup overlay if necessary.
743        StartupOverlay.getInstance().updateControlStates();
744      }
745    },
746
747    /**
748     * Handler for messages sent from the main uber page.
749     * @param {Event} e The 'message' event from the uber page.
750     * @private
751     */
752    handleWindowMessage_: function(e) {
753      if ((/** @type {{method: string}} */(e.data)).method == 'frameSelected')
754        $('search-field').focus();
755    },
756
757    /**
758     * Animatedly changes height |from| a px number |to| a px number.
759     * @param {HTMLElement} section The section to animate.
760     * @param {HTMLElement} container The container of |section|.
761     * @param {boolean} showing Whether to go from 0 -> container height or
762     *     container height -> 0.
763     * @private
764     */
765    animatedSectionHeightChange_: function(section, container, showing) {
766      // If the section is already animating, dispatch a synthetic transition
767      // end event as the upcoming code will cancel the current one.
768      if (section.classList.contains('sliding'))
769        cr.dispatchSimpleEvent(section, 'webkitTransitionEnd');
770
771      this.addTransitionEndListener_(section);
772
773      section.hidden = false;
774      section.style.height = (showing ? 0 : container.offsetHeight) + 'px';
775      section.classList.add('sliding');
776
777      // Force a style recalc before starting the animation.
778      /** @suppress {suspiciousCode} */
779      section.offsetHeight;
780
781      section.style.height = (showing ? container.offsetHeight : 0) + 'px';
782    },
783
784    /**
785     * Shows the given section.
786     * @param {HTMLElement} section The section to be shown.
787     * @param {HTMLElement} container The container for the section. Must be
788     *     inside of |section|.
789     * @param {boolean} animate Indicate if the expansion should be animated.
790     * @private
791     */
792    showSection_: function(section, container, animate) {
793      // Delay starting the transition if animating so that hidden change will
794      // be processed.
795      if (animate) {
796        this.animatedSectionHeightChange_(section, container, true);
797      } else {
798        section.hidden = false;
799        section.style.height = 'auto';
800      }
801    },
802
803    /**
804     * Shows the given section, with animation.
805     * @param {HTMLElement} section The section to be shown.
806     * @param {HTMLElement} container The container for the section. Must be
807     *     inside of |section|.
808     * @private
809     */
810    showSectionWithAnimation_: function(section, container) {
811      this.showSection_(section, container, /* animate */ true);
812    },
813
814    /**
815     * Hides the given |section| with animation.
816     * @param {HTMLElement} section The section to be hidden.
817     * @param {HTMLElement} container The container for the section. Must be
818     *     inside of |section|.
819     * @private
820     */
821    hideSectionWithAnimation_: function(section, container) {
822      this.animatedSectionHeightChange_(section, container, false);
823    },
824
825    /**
826     * Toggles the visibility of |section| in an animated way.
827     * @param {HTMLElement} section The section to be toggled.
828     * @param {HTMLElement} container The container for the section. Must be
829     *     inside of |section|.
830     * @private
831     */
832    toggleSectionWithAnimation_: function(section, container) {
833      if (BrowserOptions.shouldShowSection_(section))
834        this.showSectionWithAnimation_(section, container);
835      else
836        this.hideSectionWithAnimation_(section, container);
837    },
838
839    /**
840     * Scrolls the settings page to make the section visible auto-expanding
841     * advanced settings if required.  The transition is not animated.  This
842     * method is used to ensure that a section associated with an overlay
843     * is visible when the overlay is closed.
844     * @param {!Element} section  The section to make visible.
845     * @private
846     */
847    scrollToSection_: function(section) {
848      var advancedSettings = $('advanced-settings');
849      var container = $('advanced-settings-container');
850      var expander = $('advanced-settings-expander');
851      if (!expander.hidden &&
852          advancedSettings.hidden &&
853          section.parentNode == container) {
854        this.showSection_($('advanced-settings'),
855                          $('advanced-settings-container'),
856                          /* animate */ false);
857        this.updateAdvancedSettingsExpander_();
858      }
859
860      if (!this.initializationComplete_) {
861        var self = this;
862        var callback = function() {
863           document.removeEventListener('initializationComplete', callback);
864           self.scrollToSection_(section);
865        };
866        document.addEventListener('initializationComplete', callback);
867        return;
868      }
869
870      var pageContainer = $('page-container');
871      // pageContainer.offsetTop is relative to the screen.
872      var pageTop = pageContainer.offsetTop;
873      var sectionBottom = section.offsetTop + section.offsetHeight;
874      // section.offsetTop is relative to the 'page-container'.
875      var sectionTop = section.offsetTop;
876      if (pageTop + sectionBottom > document.body.scrollHeight ||
877          pageTop + sectionTop < 0) {
878        // Currently not all layout updates are guaranteed to precede the
879        // initializationComplete event (for example 'set-as-default-browser'
880        // button) leaving some uncertainty in the optimal scroll position.
881        // The section is placed approximately in the middle of the screen.
882        var top = Math.min(0, document.body.scrollHeight / 2 - sectionBottom);
883        pageContainer.style.top = top + 'px';
884        pageContainer.oldScrollTop = -top;
885      }
886    },
887
888    /**
889     * Adds a |webkitTransitionEnd| listener to the given section so that
890     * it can be animated. The listener will only be added to a given section
891     * once, so this can be called as multiple times.
892     * @param {HTMLElement} section The section to be animated.
893     * @private
894     */
895    addTransitionEndListener_: function(section) {
896      if (section.hasTransitionEndListener_)
897        return;
898
899      section.addEventListener('webkitTransitionEnd',
900          this.onTransitionEnd_.bind(this));
901      section.hasTransitionEndListener_ = true;
902    },
903
904    /**
905     * Called after an animation transition has ended.
906     * @param {Event} event The webkitTransitionEnd event. NOTE: May be
907     *     synthetic.
908     * @private
909     */
910    onTransitionEnd_: function(event) {
911      if (event.propertyName && event.propertyName != 'height') {
912        // If not a synthetic event or a real transition we care about, bail.
913        return;
914      }
915
916      var section = event.target;
917      section.classList.remove('sliding');
918
919      if (!event.propertyName) {
920        // Only real transitions past this point.
921        return;
922      }
923
924      if (section.style.height == '0px') {
925        // Hide the content so it can't get tab focus.
926        section.hidden = true;
927        section.style.height = '';
928      } else {
929        // Set the section height to 'auto' to allow for size changes
930        // (due to font change or dynamic content).
931        section.style.height = 'auto';
932      }
933    },
934
935    /** @private */
936    updateAdvancedSettingsExpander_: function() {
937      var expander = $('advanced-settings-expander');
938      if (BrowserOptions.shouldShowSection_($('advanced-settings')))
939        expander.textContent = loadTimeData.getString('showAdvancedSettings');
940      else
941        expander.textContent = loadTimeData.getString('hideAdvancedSettings');
942    },
943
944    /**
945     * Updates the sync section with the given state.
946     * @param {options.SyncStatus} syncData A bunch of data records that
947     *     describe the status of the sync system.
948     * @private
949     */
950    updateSyncState_: function(syncData) {
951      if (!syncData.signinAllowed &&
952          (!syncData.supervisedUser || !cr.isChromeOS)) {
953        $('sync-section').hidden = true;
954        this.maybeShowUserSection_();
955        return;
956      }
957
958      $('sync-section').hidden = false;
959      this.maybeShowUserSection_();
960
961      if (cr.isChromeOS && syncData.supervisedUser) {
962        var subSection = $('sync-section').firstChild;
963        while (subSection) {
964          if (subSection.nodeType == Node.ELEMENT_NODE)
965            subSection.hidden = true;
966          subSection = subSection.nextSibling;
967        }
968
969        $('account-picture-wrapper').hidden = false;
970        $('sync-general').hidden = false;
971        $('sync-status').hidden = true;
972
973        return;
974      }
975
976      // If the user gets signed out while the advanced sync settings dialog is
977      // visible, say, due to a dashboard clear, close the dialog.
978      // However, if the user gets signed out as a result of abandoning first
979      // time sync setup, do not call closeOverlay as it will redirect the
980      // browser to the main settings page and override any in-progress
981      // user-initiated navigation. See crbug.com/278030.
982      // Note: SyncSetupOverlay.closeOverlay is a no-op if the overlay is
983      // already hidden.
984      if (this.signedIn_ && !syncData.signedIn && !syncData.setupInProgress)
985        SyncSetupOverlay.closeOverlay();
986
987      this.signedIn_ = !!syncData.signedIn;
988
989      // Display the "advanced settings" button if we're signed in and sync is
990      // not managed/disabled. If the user is signed in, but sync is disabled,
991      // this button is used to re-enable sync.
992      var customizeSyncButton = $('customize-sync');
993      customizeSyncButton.hidden = !this.signedIn_ ||
994                                   syncData.managed ||
995                                   !syncData.syncSystemEnabled;
996
997      // Only modify the customize button's text if the new text is different.
998      // Otherwise, it can affect search-highlighting in the settings page.
999      // See http://crbug.com/268265.
1000      var customizeSyncButtonNewText = syncData.setupCompleted ?
1001          loadTimeData.getString('customizeSync') :
1002          loadTimeData.getString('syncButtonTextStart');
1003      if (customizeSyncButton.textContent != customizeSyncButtonNewText)
1004        customizeSyncButton.textContent = customizeSyncButtonNewText;
1005
1006      // Disable the "sign in" button if we're currently signing in, or if we're
1007      // already signed in and signout is not allowed.
1008      var signInButton = $('start-stop-sync');
1009      signInButton.disabled = syncData.setupInProgress;
1010      this.signoutAllowed_ = !!syncData.signoutAllowed;
1011      if (!syncData.signoutAllowed)
1012        $('start-stop-sync-indicator').setAttribute('controlled-by', 'policy');
1013      else
1014        $('start-stop-sync-indicator').removeAttribute('controlled-by');
1015
1016      // Hide the "sign in" button on Chrome OS, and show it on desktop Chrome
1017      // (except for supervised users, which can't change their signed-in
1018      // status).
1019      signInButton.hidden = cr.isChromeOS || syncData.supervisedUser;
1020
1021      signInButton.textContent =
1022          this.signedIn_ ?
1023              loadTimeData.getString('syncButtonTextStop') :
1024              syncData.setupInProgress ?
1025                  loadTimeData.getString('syncButtonTextInProgress') :
1026                  loadTimeData.getString('syncButtonTextSignIn');
1027      $('start-stop-sync-indicator').hidden = signInButton.hidden;
1028
1029      // TODO(estade): can this just be textContent?
1030      $('sync-status-text').innerHTML = syncData.statusText;
1031      var statusSet = syncData.statusText.length != 0;
1032      $('sync-overview').hidden =
1033          statusSet ||
1034          (cr.isChromeOS && UIAccountTweaks.loggedInAsPublicAccount());
1035      $('sync-status').hidden = !statusSet;
1036
1037      $('sync-action-link').textContent = syncData.actionLinkText;
1038      // Don't show the action link if it is empty or undefined.
1039      $('sync-action-link').hidden = syncData.actionLinkText.length == 0;
1040      $('sync-action-link').disabled = syncData.managed ||
1041                                       !syncData.syncSystemEnabled;
1042
1043      // On Chrome OS, sign out the user and sign in again to get fresh
1044      // credentials on auth errors.
1045      $('sync-action-link').onclick = function(event) {
1046        if (cr.isChromeOS && syncData.hasError)
1047          SyncSetupOverlay.doSignOutOnAuthError();
1048        else
1049          SyncSetupOverlay.showSetupUI();
1050      };
1051
1052      if (syncData.hasError)
1053        $('sync-status').classList.add('sync-error');
1054      else
1055        $('sync-status').classList.remove('sync-error');
1056
1057      // Disable the "customize / set up sync" button if sync has an
1058      // unrecoverable error. Also disable the button if sync has not been set
1059      // up and the user is being presented with a link to re-auth.
1060      // See crbug.com/289791.
1061      customizeSyncButton.disabled =
1062          syncData.hasUnrecoverableError ||
1063          (!syncData.setupCompleted && !$('sync-action-link').hidden);
1064    },
1065
1066    /**
1067     * Update the UI depending on whether the current profile has a pairing for
1068     * Easy Unlock.
1069     * @param {boolean} hasPairing True if the current profile has a pairing.
1070     */
1071    updateEasyUnlock_: function(hasPairing) {
1072      $('easy-unlock-setup').hidden = hasPairing;
1073      $('easy-unlock-enable').hidden = !hasPairing;
1074      if (!hasPairing && EasyUnlockTurnOffOverlay.getInstance().visible) {
1075        EasyUnlockTurnOffOverlay.dismiss();
1076      }
1077    },
1078
1079    /**
1080     * Update the UI depending on whether the current profile manages any
1081     * supervised users.
1082     * @param {boolean} show True if the current profile manages any supervised
1083     *     users.
1084     */
1085    updateManagesSupervisedUsers_: function(show) {
1086      $('profiles-supervised-dashboard-tip').hidden = !show;
1087      this.maybeShowUserSection_();
1088    },
1089
1090    /**
1091     * Get the start/stop sync button DOM element. Used for testing.
1092     * @return {Element} The start/stop sync button.
1093     * @private
1094     */
1095    getStartStopSyncButton_: function() {
1096      return $('start-stop-sync');
1097    },
1098
1099    /**
1100     * Event listener for the 'show home button' preference. Shows/hides the
1101     * UI for changing the home page with animation, unless this is the first
1102     * time this function is called, in which case there is no animation.
1103     * @param {Event} event The preference change event.
1104     */
1105    onShowHomeButtonChanged_: function(event) {
1106      var section = $('change-home-page-section');
1107      if (this.onShowHomeButtonChangedCalled_) {
1108        var container = $('change-home-page-section-container');
1109        if (event.value.value)
1110          this.showSectionWithAnimation_(section, container);
1111        else
1112          this.hideSectionWithAnimation_(section, container);
1113      } else {
1114        section.hidden = !event.value.value;
1115        this.onShowHomeButtonChangedCalled_ = true;
1116      }
1117    },
1118
1119    /**
1120     * Activates the Hotword section from the System settings page.
1121     * @param {boolean} opt_enabled Current preference state for hotwording.
1122     * @param {string} opt_error The error message to display.
1123     * @private
1124     */
1125    showHotwordSection_: function(opt_enabled, opt_error) {
1126      $('hotword-search').hidden = false;
1127      $('hotword-search-setting-indicator').setError(opt_error);
1128      if (opt_enabled && opt_error)
1129        $('hotword-search-setting-indicator').updateBasedOnError();
1130    },
1131
1132    /**
1133     * Activates the Audio History and Always-On Hotword sections from the
1134     * System settings page.
1135     * @private
1136     */
1137    showHotwordAlwaysOnSection_: function() {
1138      $('voice-section-title').hidden = false;
1139      $('hotword-always-on-search').hidden = false;
1140      $('audio-logging').hidden = false;
1141    },
1142
1143    /**
1144     * Event listener for the 'homepage is NTP' preference. Updates the label
1145     * next to the 'Change' button.
1146     * @param {Event} event The preference change event.
1147     */
1148    onHomePageIsNtpChanged_: function(event) {
1149      if (!event.value.uncommitted) {
1150        $('home-page-url').hidden = event.value.value;
1151        $('home-page-ntp').hidden = !event.value.value;
1152      }
1153    },
1154
1155    /**
1156     * Event listener for changes to the homepage preference. Updates the label
1157     * next to the 'Change' button.
1158     * @param {Event} event The preference change event.
1159     */
1160    onHomePageChanged_: function(event) {
1161      if (!event.value.uncommitted)
1162        $('home-page-url').textContent = this.stripHttp_(event.value.value);
1163    },
1164
1165    /**
1166     * Removes the 'http://' from a URL, like the omnibox does. If the string
1167     * doesn't start with 'http://' it is returned unchanged.
1168     * @param {string} url The url to be processed
1169     * @return {string} The url with the 'http://' removed.
1170     */
1171    stripHttp_: function(url) {
1172      return url.replace(/^http:\/\//, '');
1173    },
1174
1175   /**
1176    * Shows the autoLaunch preference and initializes its checkbox value.
1177    * @param {boolean} enabled Whether autolaunch is enabled or or not.
1178    * @private
1179    */
1180    updateAutoLaunchState_: function(enabled) {
1181      $('auto-launch-option').hidden = false;
1182      $('auto-launch').checked = enabled;
1183    },
1184
1185    /**
1186     * Called when the value of the download.default_directory preference
1187     * changes.
1188     * @param {Event} event Change event.
1189     * @private
1190     */
1191    onDefaultDownloadDirectoryChanged_: function(event) {
1192      $('downloadLocationPath').value = event.value.value;
1193      if (cr.isChromeOS) {
1194        // On ChromeOS, replace /special/drive-<hash>/root with "Google Drive"
1195        // for remote files, /home/chronos/user/Downloads or
1196        // /home/chronos/u-<hash>/Downloads with "Downloads" for local paths,
1197        // and '/' with ' \u203a ' (angled quote sign) everywhere. The modified
1198        // path is used only for display purpose.
1199        var path = $('downloadLocationPath').value;
1200        path = path.replace(/^\/special\/drive[^\/]*\/root/, 'Google Drive');
1201        path = path.replace(/^\/home\/chronos\/(user|u-[^\/]*)\//, '');
1202        path = path.replace(/\//g, ' \u203a ');
1203        $('downloadLocationPath').value = path;
1204      }
1205      $('download-location-label').classList.toggle('disabled',
1206                                                    event.value.disabled);
1207      $('downloadLocationChangeButton').disabled = event.value.disabled;
1208    },
1209
1210    /**
1211     * Update the Default Browsers section based on the current state.
1212     * @param {string} statusString Description of the current default state.
1213     * @param {boolean} isDefault Whether or not the browser is currently
1214     *     default.
1215     * @param {boolean} canBeDefault Whether or not the browser can be default.
1216     * @private
1217     */
1218    updateDefaultBrowserState_: function(statusString, isDefault,
1219                                         canBeDefault) {
1220      if (!cr.isChromeOS) {
1221        var label = $('default-browser-state');
1222        label.textContent = statusString;
1223
1224        $('set-as-default-browser').hidden = !canBeDefault || isDefault;
1225      }
1226    },
1227
1228    /**
1229     * Clears the search engine popup.
1230     * @private
1231     */
1232    clearSearchEngines_: function() {
1233      $('default-search-engine').textContent = '';
1234    },
1235
1236    /**
1237     * Updates the search engine popup with the given entries.
1238     * @param {Array} engines List of available search engines.
1239     * @param {number} defaultValue The value of the current default engine.
1240     * @param {boolean} defaultManaged Whether the default search provider is
1241     *     managed. If true, the default search provider can't be changed.
1242     * @private
1243     */
1244    updateSearchEngines_: function(engines, defaultValue, defaultManaged) {
1245      this.clearSearchEngines_();
1246      var engineSelect = $('default-search-engine');
1247      engineSelect.disabled = defaultManaged;
1248      if (defaultManaged && defaultValue == -1)
1249        return;
1250      var engineCount = engines.length;
1251      var defaultIndex = -1;
1252      for (var i = 0; i < engineCount; i++) {
1253        var engine = engines[i];
1254        var option = new Option(engine.name, engine.index);
1255        if (defaultValue == option.value)
1256          defaultIndex = i;
1257        engineSelect.appendChild(option);
1258      }
1259      if (defaultIndex >= 0)
1260        engineSelect.selectedIndex = defaultIndex;
1261    },
1262
1263    /**
1264     * Set the default search engine based on the popup selection.
1265     * @private
1266     */
1267    setDefaultSearchEngine_: function() {
1268      var engineSelect = $('default-search-engine');
1269      var selectedIndex = engineSelect.selectedIndex;
1270      if (selectedIndex >= 0) {
1271        var selection = engineSelect.options[selectedIndex];
1272        chrome.send('setDefaultSearchEngine', [String(selection.value)]);
1273      }
1274    },
1275
1276   /**
1277     * Sets or clear whether Chrome should Auto-launch on computer startup.
1278     * @private
1279     */
1280    handleAutoLaunchChanged_: function() {
1281      chrome.send('toggleAutoLaunch', [$('auto-launch').checked]);
1282    },
1283
1284    /**
1285     * Get the selected profile item from the profile list. This also works
1286     * correctly if the list is not displayed.
1287     * @return {?Object} The profile item object, or null if nothing is
1288     *     selected.
1289     * @private
1290     */
1291    getSelectedProfileItem_: function() {
1292      var profilesList = $('profiles-list');
1293      if (profilesList.hidden) {
1294        if (profilesList.dataModel.length > 0)
1295          return profilesList.dataModel.item(0);
1296      } else {
1297        return profilesList.selectedItem;
1298      }
1299      return null;
1300    },
1301
1302    /**
1303     * Helper function to set the status of profile view buttons to disabled or
1304     * enabled, depending on the number of profiles and selection status of the
1305     * profiles list.
1306     * @private
1307     */
1308    setProfileViewButtonsStatus_: function() {
1309      var profilesList = $('profiles-list');
1310      var selectedProfile = profilesList.selectedItem;
1311      var hasSelection = selectedProfile != null;
1312      var hasSingleProfile = profilesList.dataModel.length == 1;
1313      var isSupervised = loadTimeData.getBoolean('profileIsSupervised');
1314      $('profiles-manage').disabled = !hasSelection ||
1315          !selectedProfile.isCurrentProfile;
1316      if (hasSelection && !selectedProfile.isCurrentProfile)
1317        $('profiles-manage').title = loadTimeData.getString('currentUserOnly');
1318      else
1319        $('profiles-manage').title = '';
1320      $('profiles-delete').disabled = isSupervised ||
1321                                      (!hasSelection && !hasSingleProfile);
1322      if (OptionsPage.isSettingsApp()) {
1323        $('profiles-app-list-switch').disabled = !hasSelection ||
1324            selectedProfile.isCurrentProfile;
1325      }
1326      var importData = $('import-data');
1327      if (importData) {
1328        importData.disabled = $('import-data').disabled = hasSelection &&
1329          !selectedProfile.isCurrentProfile;
1330      }
1331    },
1332
1333    /**
1334     * Display the correct dialog layout, depending on how many profiles are
1335     * available.
1336     * @param {number} numProfiles The number of profiles to display.
1337     * @private
1338     */
1339    setProfileViewSingle_: function(numProfiles) {
1340      // Always show the profiles list when using the new Profiles UI.
1341      var usingNewProfilesUI = loadTimeData.getBoolean('usingNewProfilesUI');
1342      var showSingleProfileView = !usingNewProfilesUI && numProfiles == 1;
1343      $('profiles-list').hidden = showSingleProfileView;
1344      $('profiles-single-message').hidden = !showSingleProfileView;
1345      $('profiles-manage').hidden =
1346          showSingleProfileView || OptionsPage.isSettingsApp();
1347      $('profiles-delete').textContent = showSingleProfileView ?
1348          loadTimeData.getString('profilesDeleteSingle') :
1349          loadTimeData.getString('profilesDelete');
1350      if (OptionsPage.isSettingsApp())
1351        $('profiles-app-list-switch').hidden = showSingleProfileView;
1352    },
1353
1354    /**
1355     * Adds all |profiles| to the list.
1356     * @param {Array.<{name: string, filePath: string,
1357     *     isCurrentProfile: boolean, isSupervised: boolean}>} profiles An array
1358     *     of profile info objects.
1359     * @private
1360     */
1361    setProfilesInfo_: function(profiles) {
1362      this.setProfileViewSingle_(profiles.length);
1363      // add it to the list, even if the list is hidden so we can access it
1364      // later.
1365      $('profiles-list').dataModel = new ArrayDataModel(profiles);
1366
1367      // Received new data. If showing the "manage" overlay, keep it up to
1368      // date. If showing the "delete" overlay, close it.
1369      if (ManageProfileOverlay.getInstance().visible &&
1370          !$('manage-profile-overlay-manage').hidden) {
1371        ManageProfileOverlay.showManageDialog();
1372      } else {
1373        ManageProfileOverlay.getInstance().visible = false;
1374      }
1375
1376      this.setProfileViewButtonsStatus_();
1377    },
1378
1379    /**
1380     * Reports supervised user import errors to the SupervisedUserImportOverlay.
1381     * @param {string} error The error message to display.
1382     * @private
1383     */
1384    showSupervisedUserImportError_: function(error) {
1385      SupervisedUserImportOverlay.onError(error);
1386    },
1387
1388    /**
1389     * Reports successful importing of a supervised user to
1390     * the SupervisedUserImportOverlay.
1391     * @private
1392     */
1393    showSupervisedUserImportSuccess_: function() {
1394      SupervisedUserImportOverlay.onSuccess();
1395    },
1396
1397    /**
1398     * Reports an error to the "create" overlay during profile creation.
1399     * @param {string} error The error message to display.
1400     * @private
1401     */
1402    showCreateProfileError_: function(error) {
1403      CreateProfileOverlay.onError(error);
1404    },
1405
1406    /**
1407    * Sends a warning message to the "create" overlay during profile creation.
1408    * @param {string} warning The warning message to display.
1409    * @private
1410    */
1411    showCreateProfileWarning_: function(warning) {
1412      CreateProfileOverlay.onWarning(warning);
1413    },
1414
1415    /**
1416    * Reports successful profile creation to the "create" overlay.
1417     * @param {Object} profileInfo An object of the form:
1418     *     profileInfo = {
1419     *       name: "Profile Name",
1420     *       filePath: "/path/to/profile/data/on/disk"
1421     *       isSupervised: (true|false),
1422     *     };
1423    * @private
1424    */
1425    showCreateProfileSuccess_: function(profileInfo) {
1426      CreateProfileOverlay.onSuccess(profileInfo);
1427    },
1428
1429    /**
1430     * Returns the currently active profile for this browser window.
1431     * @return {Object} A profile info object.
1432     * @private
1433     */
1434    getCurrentProfile_: function() {
1435      for (var i = 0; i < $('profiles-list').dataModel.length; i++) {
1436        var profile = $('profiles-list').dataModel.item(i);
1437        if (profile.isCurrentProfile)
1438          return profile;
1439      }
1440
1441      assertNotReached('There should always be a current profile.');
1442    },
1443
1444    /**
1445     * Propmpts user to confirm deletion of the profile for this browser
1446     * window.
1447     * @private
1448     */
1449    deleteCurrentProfile_: function() {
1450      ManageProfileOverlay.showDeleteDialog(this.getCurrentProfile_());
1451    },
1452
1453    /**
1454     * @param {boolean} enabled
1455     */
1456    setNativeThemeButtonEnabled_: function(enabled) {
1457      var button = $('themes-native-button');
1458      if (button)
1459        button.disabled = !enabled;
1460    },
1461
1462    /**
1463     * @param {boolean} enabled
1464     */
1465    setThemesResetButtonEnabled_: function(enabled) {
1466      $('themes-reset').disabled = !enabled;
1467    },
1468
1469    /**
1470     * @param {boolean} managed
1471     */
1472    setAccountPictureManaged_: function(managed) {
1473      var picture = $('account-picture');
1474      if (managed || UIAccountTweaks.loggedInAsGuest()) {
1475        picture.disabled = true;
1476        ChangePictureOptions.closeOverlay();
1477      } else {
1478        picture.disabled = false;
1479      }
1480
1481      // Create a synthetic pref change event decorated as
1482      // CoreOptionsHandler::CreateValueForPref() does.
1483      var event = new Event('account-picture');
1484      if (managed)
1485        event.value = { controlledBy: 'policy' };
1486      else
1487        event.value = {};
1488      $('account-picture-indicator').handlePrefChange(event);
1489    },
1490
1491    /**
1492     * (Re)loads IMG element with current user account picture.
1493     * @private
1494     */
1495    updateAccountPicture_: function() {
1496      var picture = $('account-picture');
1497      if (picture) {
1498        picture.src = 'chrome://userimage/' + this.username_ + '?id=' +
1499            Date.now();
1500      }
1501    },
1502
1503    /**
1504     * @param {boolean} managed
1505     */
1506    setWallpaperManaged_: function(managed) {
1507      var button = $('set-wallpaper');
1508      button.disabled = !!managed;
1509
1510      // Create a synthetic pref change event decorated as
1511      // CoreOptionsHandler::CreateValueForPref() does.
1512      var event = new Event('wallpaper');
1513      if (managed)
1514        event.value = { controlledBy: 'policy' };
1515      else
1516        event.value = {};
1517      $('wallpaper-indicator').handlePrefChange(event);
1518    },
1519
1520    /**
1521     * Handle the 'add device' button click.
1522     * @private
1523     */
1524    handleAddBluetoothDevice_: function() {
1525      chrome.send('findBluetoothDevices');
1526      PageManager.showPageByName('bluetooth', false);
1527    },
1528
1529    /**
1530     * Enables or disables the Manage SSL Certificates button.
1531     * @private
1532     */
1533    enableCertificateButton_: function(enabled) {
1534      $('certificatesManageButton').disabled = !enabled;
1535    },
1536
1537    /**
1538     * Enables or disables the ChromeOS display settings button.
1539     * @private
1540     */
1541    enableDisplayButton_: function(enabled) {
1542      if (cr.isChromeOS)
1543        $('display-options').disabled = !enabled;
1544    },
1545
1546    /**
1547     * Enables factory reset section.
1548     * @private
1549     */
1550    enableFactoryResetSection_: function() {
1551      $('factory-reset-section').hidden = false;
1552    },
1553
1554    /**
1555     * Set the checked state of the metrics reporting checkbox.
1556     * @private
1557     */
1558    setMetricsReportingCheckboxState_: function(checked, disabled) {
1559      $('metricsReportingEnabled').checked = checked;
1560      $('metricsReportingEnabled').disabled = disabled;
1561
1562      // If checkbox gets disabled then add an attribute for displaying the
1563      // special icon. The opposite shouldn't be possible to do.
1564      if (disabled) {
1565        $('metrics-reporting-disabled-icon').setAttribute('controlled-by',
1566                                                          'policy');
1567      }
1568    },
1569
1570    /**
1571     * @private
1572     */
1573    setMetricsReportingSettingVisibility_: function(visible) {
1574      if (visible)
1575        $('metricsReportingSetting').style.display = 'block';
1576      else
1577        $('metricsReportingSetting').style.display = 'none';
1578    },
1579
1580    /**
1581     * Set network prediction checkbox value.
1582     *
1583     * @param {{value: number, disabled: boolean}} pref Information about
1584     *     network prediction options. |pref.value| is the value of network
1585     *     prediction options. |pref.disabled| shows if the pref is not user
1586     *     modifiable.
1587     * @private
1588     */
1589    setNetworkPredictionValue_: function(pref) {
1590      var checkbox = $('networkPredictionOptions');
1591      checkbox.disabled = pref.disabled;
1592      if (pref.value == NetworkPredictionOptions.UNSET) {
1593        checkbox.checked = (NetworkPredictionOptions.DEFAULT !=
1594            NetworkPredictionOptions.NEVER);
1595      } else {
1596        checkbox.checked = (pref.value != NetworkPredictionOptions.NEVER);
1597      }
1598    },
1599
1600    /**
1601     * Set the font size selected item. This item actually reflects two
1602     * preferences: the default font size and the default fixed font size.
1603     *
1604     * @param {{value: number, disabled: boolean, controlledBy: string}} pref
1605     *     Information about the font size preferences. |pref.value| is the
1606     *     value of the default font size pref. |pref.disabled| is true if
1607     *     either pref not user modifiable. |pref.controlledBy| is the source of
1608     *     the pref value(s) if either pref is currently not controlled by the
1609     *     user.
1610     * @private
1611     */
1612    setFontSize_: function(pref) {
1613      var selectCtl = $('defaultFontSize');
1614      selectCtl.disabled = pref.disabled;
1615      // Create a synthetic pref change event decorated as
1616      // CoreOptionsHandler::CreateValueForPref() does.
1617      var event = new Event('synthetic-font-size');
1618      event.value = {
1619        value: pref.value,
1620        controlledBy: pref.controlledBy,
1621        disabled: pref.disabled
1622      };
1623      $('font-size-indicator').handlePrefChange(event);
1624
1625      for (var i = 0; i < selectCtl.options.length; i++) {
1626        if (selectCtl.options[i].value == pref.value) {
1627          selectCtl.selectedIndex = i;
1628          if ($('Custom'))
1629            selectCtl.remove($('Custom').index);
1630          return;
1631        }
1632      }
1633
1634      // Add/Select Custom Option in the font size label list.
1635      if (!$('Custom')) {
1636        var option = new Option(loadTimeData.getString('fontSizeLabelCustom'),
1637                                -1, false, true);
1638        option.setAttribute('id', 'Custom');
1639        selectCtl.add(option);
1640      }
1641      $('Custom').selected = true;
1642    },
1643
1644    /**
1645     * Populate the page zoom selector with values received from the caller.
1646     * @param {Array} items An array of items to populate the selector.
1647     *     each object is an array with three elements as follows:
1648     *       0: The title of the item (string).
1649     *       1: The value of the item (number).
1650     *       2: Whether the item should be selected (boolean).
1651     * @private
1652     */
1653    setupPageZoomSelector_: function(items) {
1654      var element = $('defaultZoomFactor');
1655
1656      // Remove any existing content.
1657      element.textContent = '';
1658
1659      // Insert new child nodes into select element.
1660      var value, title, selected;
1661      for (var i = 0; i < items.length; i++) {
1662        title = items[i][0];
1663        value = items[i][1];
1664        selected = items[i][2];
1665        element.appendChild(new Option(title, value, false, selected));
1666      }
1667    },
1668
1669    /**
1670     * Shows/hides the autoOpenFileTypesResetToDefault button and label, with
1671     * animation.
1672     * @param {boolean} display Whether to show the button and label or not.
1673     * @private
1674     */
1675    setAutoOpenFileTypesDisplayed_: function(display) {
1676      if ($('advanced-settings').hidden) {
1677        // If the Advanced section is hidden, don't animate the transition.
1678        $('auto-open-file-types-section').hidden = !display;
1679      } else {
1680        if (display) {
1681          this.showSectionWithAnimation_(
1682              $('auto-open-file-types-section'),
1683              $('auto-open-file-types-container'));
1684        } else {
1685          this.hideSectionWithAnimation_(
1686              $('auto-open-file-types-section'),
1687              $('auto-open-file-types-container'));
1688        }
1689      }
1690    },
1691
1692    /**
1693     * Set the enabled state for the proxy settings button and its associated
1694     * message when extension controlled.
1695     * @param {boolean} disabled Whether the button should be disabled.
1696     * @param {boolean} extensionControlled Whether the proxy is extension
1697     *     controlled.
1698     * @private
1699     */
1700    setupProxySettingsButton_: function(disabled, extensionControlled) {
1701      if (!cr.isChromeOS) {
1702        $('proxiesConfigureButton').disabled = disabled;
1703        $('proxiesLabel').textContent =
1704            loadTimeData.getString(extensionControlled ?
1705                'proxiesLabelExtension' : 'proxiesLabelSystem');
1706      }
1707    },
1708
1709    /**
1710     * Set the initial state of the spoken feedback checkbox.
1711     * @private
1712     */
1713    setSpokenFeedbackCheckboxState_: function(checked) {
1714      $('accessibility-spoken-feedback-check').checked = checked;
1715    },
1716
1717    /**
1718     * Set the initial state of the high contrast checkbox.
1719     * @private
1720     */
1721    setHighContrastCheckboxState_: function(checked) {
1722      $('accessibility-high-contrast-check').checked = checked;
1723    },
1724
1725    /**
1726     * Set the initial state of the virtual keyboard checkbox.
1727     * @private
1728     */
1729    setVirtualKeyboardCheckboxState_: function(checked) {
1730      // TODO(zork): Update UI
1731    },
1732
1733    /**
1734     * Show/hide mouse settings slider.
1735     * @private
1736     */
1737    showMouseControls_: function(show) {
1738      $('mouse-settings').hidden = !show;
1739    },
1740
1741    /**
1742     * Adds hidden warning boxes for settings potentially controlled by
1743     * extensions.
1744     * @param {string} parentDiv The div name to append the bubble to.
1745     * @param {string} bubbleId The ID to use for the bubble.
1746     * @param {boolean} first Add as first node if true, otherwise last.
1747     * @private
1748     */
1749    addExtensionControlledBox_: function(parentDiv, bubbleId, first) {
1750      var bubble = $('extension-controlled-warning-template').cloneNode(true);
1751      bubble.id = bubbleId;
1752      var parent = $(parentDiv);
1753      if (first)
1754        parent.insertBefore(bubble, parent.firstChild);
1755      else
1756        parent.appendChild(bubble);
1757    },
1758
1759    /**
1760     * Adds a bubble showing that an extension is controlling a particular
1761     * setting.
1762     * @param {string} parentDiv The div name to append the bubble to.
1763     * @param {string} bubbleId The ID to use for the bubble.
1764     * @param {string} extensionId The ID of the controlling extension.
1765     * @param {string} extensionName The name of the controlling extension.
1766     * @private
1767     */
1768    toggleExtensionControlledBox_: function(
1769        parentDiv, bubbleId, extensionId, extensionName) {
1770      var bubble = $(bubbleId);
1771      assert(bubble);
1772      bubble.hidden = extensionId.length == 0;
1773      if (bubble.hidden)
1774        return;
1775
1776      // Set the extension image.
1777      var div = bubble.firstElementChild;
1778      div.style.backgroundImage =
1779          'url(chrome://extension-icon/' + extensionId + '/24/1)';
1780
1781      // Set the bubble label.
1782      var label = loadTimeData.getStringF('extensionControlled', extensionName);
1783      var docFrag = parseHtmlSubset('<div>' + label + '</div>', ['B', 'DIV']);
1784      div.innerHTML = docFrag.firstChild.innerHTML;
1785
1786      // Wire up the button to disable the right extension.
1787      var button = div.nextElementSibling;
1788      button.dataset.extensionId = extensionId;
1789    },
1790
1791    /**
1792     * Toggles the warning boxes that show which extension is controlling
1793     * various settings of Chrome.
1794     * @param {object} details A dictionary of ID+name pairs for each of the
1795     *     settings controlled by an extension.
1796     * @private
1797     */
1798    toggleExtensionIndicators_: function(details) {
1799      this.toggleExtensionControlledBox_('search-section-content',
1800                                         'search-engine-controlled',
1801                                         details.searchEngine.id,
1802                                         details.searchEngine.name);
1803      this.toggleExtensionControlledBox_('extension-controlled-container',
1804                                         'homepage-controlled',
1805                                         details.homePage.id,
1806                                         details.homePage.name);
1807      this.toggleExtensionControlledBox_('startup-section-content',
1808                                         'startpage-controlled',
1809                                         details.startUpPage.id,
1810                                         details.startUpPage.name);
1811      this.toggleExtensionControlledBox_('newtab-section-content',
1812                                         'newtab-controlled',
1813                                         details.newTabPage.id,
1814                                         details.newTabPage.name);
1815      this.toggleExtensionControlledBox_('proxy-section-content',
1816                                         'proxy-controlled',
1817                                         details.proxy.id,
1818                                         details.proxy.name);
1819
1820      // The proxy section contains just the warning box and nothing else, so
1821      // if we're hiding the proxy warning box, we should also hide its header
1822      // section.
1823      $('proxy-section').hidden = details.proxy.id.length == 0;
1824    },
1825
1826
1827    /**
1828     * Show/hide touchpad-related settings.
1829     * @private
1830     */
1831    showTouchpadControls_: function(show) {
1832      $('touchpad-settings').hidden = !show;
1833      $('accessibility-tap-dragging').hidden = !show;
1834    },
1835
1836    /**
1837     * Activate the Bluetooth settings section on the System settings page.
1838     * @private
1839     */
1840    showBluetoothSettings_: function() {
1841      $('bluetooth-devices').hidden = false;
1842    },
1843
1844    /**
1845     * Dectivates the Bluetooth settings section from the System settings page.
1846     * @private
1847     */
1848    hideBluetoothSettings_: function() {
1849      $('bluetooth-devices').hidden = true;
1850    },
1851
1852    /**
1853     * Sets the state of the checkbox indicating if Bluetooth is turned on. The
1854     * state of the "Find devices" button and the list of discovered devices may
1855     * also be affected by a change to the state.
1856     * @param {boolean} checked Flag Indicating if Bluetooth is turned on.
1857     * @private
1858     */
1859    setBluetoothState_: function(checked) {
1860      $('enable-bluetooth').checked = checked;
1861      $('bluetooth-paired-devices-list').parentNode.hidden = !checked;
1862      $('bluetooth-add-device').hidden = !checked;
1863      $('bluetooth-reconnect-device').hidden = !checked;
1864      // Flush list of previously discovered devices if bluetooth is turned off.
1865      if (!checked) {
1866        $('bluetooth-paired-devices-list').clear();
1867        $('bluetooth-unpaired-devices-list').clear();
1868      } else {
1869        chrome.send('getPairedBluetoothDevices');
1870      }
1871    },
1872
1873    /**
1874     * Adds an element to the list of available Bluetooth devices. If an element
1875     * with a matching address is found, the existing element is updated.
1876     * @param {{name: string,
1877     *          address: string,
1878     *          paired: boolean,
1879     *          connected: boolean}} device
1880     *     Decription of the Bluetooth device.
1881     * @private
1882     */
1883    addBluetoothDevice_: function(device) {
1884      var list = $('bluetooth-unpaired-devices-list');
1885      // Display the "connecting" (already paired or not yet paired) and the
1886      // paired devices in the same list.
1887      if (device.paired || device.connecting) {
1888        // Test to see if the device is currently in the unpaired list, in which
1889        // case it should be removed from that list.
1890        var index = $('bluetooth-unpaired-devices-list').find(device.address);
1891        if (index != undefined)
1892          $('bluetooth-unpaired-devices-list').deleteItemAtIndex(index);
1893        list = $('bluetooth-paired-devices-list');
1894      } else {
1895        // Test to see if the device is currently in the paired list, in which
1896        // case it should be removed from that list.
1897        var index = $('bluetooth-paired-devices-list').find(device.address);
1898        if (index != undefined)
1899          $('bluetooth-paired-devices-list').deleteItemAtIndex(index);
1900      }
1901      list.appendDevice(device);
1902
1903      // One device can be in the process of pairing.  If found, display
1904      // the Bluetooth pairing overlay.
1905      if (device.pairing)
1906        BluetoothPairing.showDialog(device);
1907    },
1908
1909    /**
1910     * Removes an element from the list of available devices.
1911     * @param {string} address Unique address of the device.
1912     * @private
1913     */
1914    removeBluetoothDevice_: function(address) {
1915      var index = $('bluetooth-unpaired-devices-list').find(address);
1916      if (index != undefined) {
1917        $('bluetooth-unpaired-devices-list').deleteItemAtIndex(index);
1918      } else {
1919        index = $('bluetooth-paired-devices-list').find(address);
1920        if (index != undefined)
1921          $('bluetooth-paired-devices-list').deleteItemAtIndex(index);
1922      }
1923    },
1924
1925    /**
1926     * Shows the overlay dialog for changing the user avatar image.
1927     * @private
1928     */
1929    showImagerPickerOverlay_: function() {
1930      PageManager.showPageByName('changePicture');
1931    },
1932
1933    /**
1934     * Shows (or not) the "User" section of the settings page based on whether
1935     * any of the sub-sections are present (or not).
1936     * @private
1937     */
1938    maybeShowUserSection_: function() {
1939      $('sync-users-section').hidden =
1940          $('profiles-section').hidden &&
1941          $('sync-section').hidden &&
1942          $('profiles-supervised-dashboard-tip').hidden;
1943    },
1944
1945    /**
1946     * Updates the date and time section with time sync information.
1947     * @param {boolean} canSetTime Whether the system time can be set.
1948     * @private
1949     */
1950    setCanSetTime_: function(canSetTime) {
1951      // If the time has been network-synced, it cannot be set manually.
1952      $('time-synced-explanation').hidden = canSetTime;
1953      $('set-time').hidden = !canSetTime;
1954    },
1955
1956    /**
1957     * Handle the 'set date and time' button click.
1958     * @private
1959     */
1960    handleSetTime_: function() {
1961      chrome.send('showSetTime');
1962    },
1963  };
1964
1965  //Forward public APIs to private implementations.
1966  cr.makePublic(BrowserOptions, [
1967    'addBluetoothDevice',
1968    'deleteCurrentProfile',
1969    'enableCertificateButton',
1970    'enableDisplayButton',
1971    'enableFactoryResetSection',
1972    'getCurrentProfile',
1973    'getStartStopSyncButton',
1974    'hideBluetoothSettings',
1975    'notifyInitializationComplete',
1976    'removeBluetoothDevice',
1977    'scrollToSection',
1978    'setAccountPictureManaged',
1979    'setWallpaperManaged',
1980    'setAutoOpenFileTypesDisplayed',
1981    'setBluetoothState',
1982    'setCanSetTime',
1983    'setFontSize',
1984    'setNativeThemeButtonEnabled',
1985    'setNetworkPredictionValue',
1986    'setHighContrastCheckboxState',
1987    'setMetricsReportingCheckboxState',
1988    'setMetricsReportingSettingVisibility',
1989    'setProfilesInfo',
1990    'setSpokenFeedbackCheckboxState',
1991    'setThemesResetButtonEnabled',
1992    'setVirtualKeyboardCheckboxState',
1993    'setupPageZoomSelector',
1994    'setupProxySettingsButton',
1995    'showBluetoothSettings',
1996    'showCreateProfileError',
1997    'showCreateProfileSuccess',
1998    'showCreateProfileWarning',
1999    'showHotwordAlwaysOnSection',
2000    'showHotwordSection',
2001    'showMouseControls',
2002    'showSupervisedUserImportError',
2003    'showSupervisedUserImportSuccess',
2004    'showTouchpadControls',
2005    'toggleExtensionIndicators',
2006    'updateAccountPicture',
2007    'updateAutoLaunchState',
2008    'updateDefaultBrowserState',
2009    'updateEasyUnlock',
2010    'updateManagesSupervisedUsers',
2011    'updateSearchEngines',
2012    'updateSyncState',
2013  ]);
2014
2015  if (cr.isChromeOS) {
2016    /**
2017     * Returns username (canonical email) of the user logged in (ChromeOS only).
2018     * @return {string} user email.
2019     */
2020    // TODO(jhawkins): Investigate the use case for this method.
2021    BrowserOptions.getLoggedInUsername = function() {
2022      return BrowserOptions.getInstance().username_;
2023    };
2024
2025    /**
2026     * Shows different button text for each consumer management enrollment
2027     * status.
2028     * @enum {string} status Consumer management service status string.
2029     */
2030    BrowserOptions.setConsumerManagementStatus = function(status) {
2031      var button = $('consumer-management-button');
2032      if (status == 'StatusUnknown') {
2033        button.hidden = true;
2034        return;
2035      }
2036
2037      button.hidden = false;
2038      var strId;
2039      switch (status) {
2040        case ConsumerManagementOverlay.Status.STATUS_UNENROLLED:
2041          strId = 'consumerManagementEnrollButton';
2042          button.disabled = false;
2043          ConsumerManagementOverlay.setStatus(status);
2044          break;
2045        case ConsumerManagementOverlay.Status.STATUS_ENROLLING:
2046          strId = 'consumerManagementEnrollingButton';
2047          button.disabled = true;
2048          break;
2049        case ConsumerManagementOverlay.Status.STATUS_ENROLLED:
2050          strId = 'consumerManagementUnenrollButton';
2051          button.disabled = false;
2052          ConsumerManagementOverlay.setStatus(status);
2053          break;
2054        case ConsumerManagementOverlay.Status.STATUS_UNENROLLING:
2055          strId = 'consumerManagementUnenrollingButton';
2056          button.disabled = true;
2057          break;
2058      }
2059      button.textContent = loadTimeData.getString(strId);
2060    };
2061  }
2062
2063  // Export
2064  return {
2065    BrowserOptions: BrowserOptions
2066  };
2067});
2068