Home | History | Annotate | Download | only in resources
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 cr.define('options', function() {
      6   /** @const */ var OptionsPage = options.OptionsPage;
      7 
      8   // True if the synced account uses a custom passphrase.
      9   var usePassphrase_ = false;
     10 
     11   // True if the synced account uses 'encrypt everything'.
     12   var useEncryptEverything_ = false;
     13 
     14   // An object used as a cache of the arguments passed in while initially
     15   // displaying the advanced sync settings dialog. Used to switch between the
     16   // options in the main drop-down menu. Reset when the dialog is closed.
     17   var syncConfigureArgs_ = null;
     18 
     19   // A dictionary that maps the sync data type checkbox names to their checked
     20   // state. Initialized when the advanced settings dialog is first brought up,
     21   // updated any time a box is checked / unchecked, and reset when the dialog is
     22   // closed. Used to restore checkbox state while switching between the options
     23   // in the main drop-down menu. All checkboxes are checked and disabled when
     24   // the "Sync everything" menu-item is selected, and unchecked and disabled
     25   // when "Sync nothing" is selected. When "Choose what to sync" is selected,
     26   // the boxes are restored to their most recent checked state from this cache.
     27   var dataTypeBoxes_ = {};
     28 
     29   // Used to determine whether to bring the OK button / passphrase field into
     30   // focus.
     31   var confirmPageVisible_ = false;
     32   var customizePageVisible_ = false;
     33 
     34   /**
     35    * The user's selection in the synced data type drop-down menu, as an index.
     36    * @enum {number}
     37    * @const
     38    */
     39   var DataTypeSelection = {
     40     SYNC_EVERYTHING: 0,
     41     CHOOSE_WHAT_TO_SYNC: 1,
     42     SYNC_NOTHING: 2
     43   };
     44 
     45   /**
     46    * SyncSetupOverlay class
     47    * Encapsulated handling of the 'Sync Setup' overlay page.
     48    * @class
     49    */
     50   function SyncSetupOverlay() {
     51     OptionsPage.call(this, 'syncSetup',
     52                      loadTimeData.getString('syncSetupOverlayTabTitle'),
     53                      'sync-setup-overlay');
     54   }
     55 
     56   cr.addSingletonGetter(SyncSetupOverlay);
     57 
     58   SyncSetupOverlay.prototype = {
     59     __proto__: OptionsPage.prototype,
     60 
     61     /**
     62      * Initializes the page.
     63      */
     64     initializePage: function() {
     65       OptionsPage.prototype.initializePage.call(this);
     66 
     67       var self = this;
     68       $('basic-encryption-option').onchange =
     69           $('full-encryption-option').onchange = function() {
     70         self.onEncryptionRadioChanged_();
     71       }
     72       $('choose-datatypes-cancel').onclick =
     73           $('confirm-everything-cancel').onclick =
     74           $('stop-syncing-cancel').onclick =
     75           $('sync-spinner-cancel').onclick = function() {
     76         self.closeOverlay_();
     77       };
     78       $('confirm-everything-ok').onclick = function() {
     79         self.sendConfiguration_();
     80       };
     81       $('timeout-ok').onclick = function() {
     82         chrome.send('CloseTimeout');
     83         self.closeOverlay_();
     84       };
     85       $('stop-syncing-ok').onclick = function() {
     86         var deleteProfile = $('delete-profile') != undefined &&
     87             $('delete-profile').checked;
     88         chrome.send('SyncSetupStopSyncing', [deleteProfile]);
     89         self.closeOverlay_();
     90       };
     91     },
     92 
     93     showOverlay_: function() {
     94       OptionsPage.navigateToPage('syncSetup');
     95     },
     96 
     97     closeOverlay_: function() {
     98       this.syncConfigureArgs_ = null;
     99       this.dataTypeBoxes_ = {};
    100 
    101       var overlay = $('sync-setup-overlay');
    102       if (!overlay.hidden)
    103         OptionsPage.closeOverlay();
    104     },
    105 
    106     /** @override */
    107     didShowPage: function() {
    108       chrome.send('SyncSetupShowSetupUI');
    109     },
    110 
    111     /** @override */
    112     didClosePage: function() {
    113       chrome.send('SyncSetupDidClosePage');
    114     },
    115 
    116     onEncryptionRadioChanged_: function() {
    117       var visible = $('full-encryption-option').checked;
    118       $('sync-custom-passphrase').hidden = !visible;
    119       chrome.send('coreOptionsUserMetricsAction',
    120                   ['Options_SyncSetEncryption']);
    121     },
    122 
    123     /**
    124      * Sets the checked state of the individual sync data type checkboxes in the
    125      * advanced sync settings dialog.
    126      * @param {boolean} value True for checked, false for unchecked.
    127      * @private
    128      */
    129     checkAllDataTypeCheckboxes_: function(value) {
    130       // Only check / uncheck the visible ones (since there's no way to uncheck
    131       // / check the invisible ones).
    132       var checkboxes = $('choose-data-types-body').querySelectorAll(
    133           '.sync-type-checkbox:not([hidden]) input');
    134       for (var i = 0; i < checkboxes.length; i++) {
    135         checkboxes[i].checked = value;
    136       }
    137     },
    138 
    139     /**
    140      * Restores the checked states of the sync data type checkboxes in the
    141      * advanced sync settings dialog. Called when "Choose what to sync" is
    142      * selected. Required because all the checkboxes are checked when
    143      * "Sync everything" is selected, and unchecked when "Sync nothing" is
    144      * selected. Note: We only restore checkboxes for data types that are
    145      * actually visible and whose old values are found in the cache, since it's
    146      * possible for some data types to not be registered, and therefore, their
    147      * checkboxes remain hidden, and never get cached.
    148      * @private
    149      */
    150     restoreDataTypeCheckboxes_: function() {
    151       for (dataType in dataTypeBoxes_) {
    152         $(dataType).checked = dataTypeBoxes_[dataType];
    153       }
    154     },
    155 
    156     /**
    157      * Enables / grays out the sync data type checkboxes in the advanced
    158      * settings dialog.
    159      * @param {boolean} enabled True for enabled, false for grayed out.
    160      * @private
    161      */
    162     setDataTypeCheckboxesEnabled_: function(enabled) {
    163       var checkboxes = $('choose-data-types-body').querySelectorAll('input');
    164       for (var i = 0; i < checkboxes.length; i++) {
    165         checkboxes[i].disabled = !enabled;
    166       }
    167     },
    168 
    169     /**
    170      * Sets the state of the sync data type checkboxes based on whether "Sync
    171      * everything", "Choose what to sync", or "Sync nothing" are selected in the
    172      * drop-down menu of the advanced settings dialog.
    173      * @param {cr.DataTypeSelection} selectedIndex Index of user's selection.
    174      * @private
    175      */
    176     setDataTypeCheckboxes_: function(selectedIndex) {
    177       if (selectedIndex == DataTypeSelection.CHOOSE_WHAT_TO_SYNC) {
    178         this.setDataTypeCheckboxesEnabled_(true);
    179         this.restoreDataTypeCheckboxes_();
    180       } else {
    181         this.setDataTypeCheckboxesEnabled_(false);
    182         this.checkAllDataTypeCheckboxes_(selectedIndex ==
    183                                          DataTypeSelection.SYNC_EVERYTHING);
    184       }
    185     },
    186 
    187     checkPassphraseMatch_: function() {
    188       var emptyError = $('empty-error');
    189       var mismatchError = $('mismatch-error');
    190       emptyError.hidden = true;
    191       mismatchError.hidden = true;
    192 
    193       var f = $('choose-data-types-form');
    194       if (!$('full-encryption-option').checked ||
    195            $('basic-encryption-option').disabled) {
    196         return true;
    197       }
    198 
    199       var customPassphrase = $('custom-passphrase');
    200       if (customPassphrase.value.length == 0) {
    201         emptyError.hidden = false;
    202         return false;
    203       }
    204 
    205       var confirmPassphrase = $('confirm-passphrase');
    206       if (confirmPassphrase.value != customPassphrase.value) {
    207         mismatchError.hidden = false;
    208         return false;
    209       }
    210 
    211       return true;
    212     },
    213 
    214     sendConfiguration_: function() {
    215       var encryptAllData = $('full-encryption-option').checked;
    216 
    217       var usePassphrase;
    218       var customPassphrase;
    219       var googlePassphrase = false;
    220       if (!$('sync-existing-passphrase-container').hidden) {
    221         // If we were prompted for an existing passphrase, use it.
    222         customPassphrase = $('choose-data-types-form').passphrase.value;
    223         usePassphrase = true;
    224         // If we were displaying the 'enter your old google password' prompt,
    225         // then that means this is the user's google password.
    226         googlePassphrase = !$('google-passphrase-needed-body').hidden;
    227         // We allow an empty passphrase, in case the user has disabled
    228         // all their encrypted datatypes. In that case, the PSS will accept
    229         // the passphrase and finish configuration. If the user has enabled
    230         // encrypted datatypes, the PSS will prompt again specifying that the
    231         // passphrase failed.
    232       } else if (!$('basic-encryption-option').disabled &&
    233                   $('full-encryption-option').checked) {
    234         // The user is setting a custom passphrase for the first time.
    235         if (!this.checkPassphraseMatch_())
    236           return;
    237         customPassphrase = $('custom-passphrase').value;
    238         usePassphrase = true;
    239       } else {
    240         // The user is not setting a custom passphrase.
    241         usePassphrase = false;
    242       }
    243 
    244       // Don't allow the user to tweak the settings once we send the
    245       // configuration to the backend.
    246       this.setInputElementsDisabledState_(true);
    247       $('use-default-link').hidden = true;
    248       $('use-default-link').disabled = true;
    249       $('use-default-link').onclick = null;
    250 
    251       // These values need to be kept in sync with where they are read in
    252       // SyncSetupFlow::GetDataTypeChoiceData().
    253       var syncAll = $('sync-select-datatypes').selectedIndex ==
    254                     DataTypeSelection.SYNC_EVERYTHING;
    255       var syncNothing = $('sync-select-datatypes').selectedIndex ==
    256                         DataTypeSelection.SYNC_NOTHING;
    257       var result = JSON.stringify({
    258         'syncAllDataTypes': syncAll,
    259         'syncNothing': syncNothing,
    260         'bookmarksSynced': syncAll || $('bookmarks-checkbox').checked,
    261         'preferencesSynced': syncAll || $('preferences-checkbox').checked,
    262         'themesSynced': syncAll || $('themes-checkbox').checked,
    263         'passwordsSynced': syncAll || $('passwords-checkbox').checked,
    264         'autofillSynced': syncAll || $('autofill-checkbox').checked,
    265         'extensionsSynced': syncAll || $('extensions-checkbox').checked,
    266         'typedUrlsSynced': syncAll || $('typed-urls-checkbox').checked,
    267         'appsSynced': syncAll || $('apps-checkbox').checked,
    268         'tabsSynced': syncAll || $('tabs-checkbox').checked,
    269         'encryptAllData': encryptAllData,
    270         'usePassphrase': usePassphrase,
    271         'isGooglePassphrase': googlePassphrase,
    272         'passphrase': customPassphrase
    273       });
    274       chrome.send('SyncSetupConfigure', [result]);
    275     },
    276 
    277     /**
    278      * Sets the disabled property of all input elements within the 'Customize
    279      * Sync Preferences' screen. This is used to prohibit the user from changing
    280      * the inputs after confirming the customized sync preferences, or resetting
    281      * the state when re-showing the dialog.
    282      * @param {boolean} disabled True if controls should be set to disabled.
    283      * @private
    284      */
    285     setInputElementsDisabledState_: function(disabled) {
    286       var configureElements =
    287           $('customize-sync-preferences').querySelectorAll('input');
    288       for (var i = 0; i < configureElements.length; i++)
    289         configureElements[i].disabled = disabled;
    290       $('sync-select-datatypes').disabled = disabled;
    291 
    292       $('customize-link').hidden = disabled;
    293       $('customize-link').disabled = disabled;
    294       $('customize-link').onclick = (disabled ? null : function() {
    295         SyncSetupOverlay.showCustomizePage(null,
    296                                            DataTypeSelection.SYNC_EVERYTHING);
    297         return false;
    298       });
    299     },
    300 
    301     /**
    302      * Shows or hides the sync data type checkboxes in the advanced sync
    303      * settings dialog. Also initializes |dataTypeBoxes_| with their values, and
    304      * makes their onclick handlers update |dataTypeBoxes_|.
    305      * @param {Object} args The configuration data used to show/hide UI.
    306      * @private
    307      */
    308     setChooseDataTypesCheckboxes_: function(args) {
    309       var datatypeSelect = $('sync-select-datatypes');
    310       datatypeSelect.selectedIndex = args.syncAllDataTypes ?
    311                                          DataTypeSelection.SYNC_EVERYTHING :
    312                                          DataTypeSelection.CHOOSE_WHAT_TO_SYNC;
    313 
    314       $('bookmarks-checkbox').checked = args.bookmarksSynced;
    315       dataTypeBoxes_['bookmarks-checkbox'] = args.bookmarksSynced;
    316       $('bookmarks-checkbox').onclick = this.handleDataTypeClick_;
    317 
    318       $('preferences-checkbox').checked = args.preferencesSynced;
    319       dataTypeBoxes_['preferences-checkbox'] = args.preferencesSynced;
    320       $('preferences-checkbox').onclick = this.handleDataTypeClick_;
    321 
    322       $('themes-checkbox').checked = args.themesSynced;
    323       dataTypeBoxes_['themes-checkbox'] = args.themesSynced;
    324       $('themes-checkbox').onclick = this.handleDataTypeClick_;
    325 
    326       if (args.passwordsRegistered) {
    327         $('passwords-checkbox').checked = args.passwordsSynced;
    328         dataTypeBoxes_['passwords-checkbox'] = args.passwordsSynced;
    329         $('passwords-checkbox').onclick = this.handleDataTypeClick_;
    330         $('passwords-item').hidden = false;
    331       } else {
    332         $('passwords-item').hidden = true;
    333       }
    334       if (args.autofillRegistered) {
    335         $('autofill-checkbox').checked = args.autofillSynced;
    336         dataTypeBoxes_['autofill-checkbox'] = args.autofillSynced;
    337         $('autofill-checkbox').onclick = this.handleDataTypeClick_;
    338         $('autofill-item').hidden = false;
    339       } else {
    340         $('autofill-item').hidden = true;
    341       }
    342       if (args.extensionsRegistered) {
    343         $('extensions-checkbox').checked = args.extensionsSynced;
    344         dataTypeBoxes_['extensions-checkbox'] = args.extensionsSynced;
    345         $('extensions-checkbox').onclick = this.handleDataTypeClick_;
    346         $('extensions-item').hidden = false;
    347       } else {
    348         $('extensions-item').hidden = true;
    349       }
    350       if (args.typedUrlsRegistered) {
    351         $('typed-urls-checkbox').checked = args.typedUrlsSynced;
    352         dataTypeBoxes_['typed-urls-checkbox'] = args.typedUrlsSynced;
    353         $('typed-urls-checkbox').onclick = this.handleDataTypeClick_;
    354         $('omnibox-item').hidden = false;
    355       } else {
    356         $('omnibox-item').hidden = true;
    357       }
    358       if (args.appsRegistered) {
    359         $('apps-checkbox').checked = args.appsSynced;
    360         dataTypeBoxes_['apps-checkbox'] = args.appsSynced;
    361         $('apps-checkbox').onclick = this.handleDataTypeClick_;
    362         $('apps-item').hidden = false;
    363       } else {
    364         $('apps-item').hidden = true;
    365       }
    366       if (args.tabsRegistered) {
    367         $('tabs-checkbox').checked = args.tabsSynced;
    368         dataTypeBoxes_['tabs-checkbox'] = args.tabsSynced;
    369         $('tabs-checkbox').onclick = this.handleDataTypeClick_;
    370         $('tabs-item').hidden = false;
    371       } else {
    372         $('tabs-item').hidden = true;
    373       }
    374 
    375       this.setDataTypeCheckboxes_(datatypeSelect.selectedIndex);
    376     },
    377 
    378     /**
    379      * Updates the cached values of the sync data type checkboxes stored in
    380      * |dataTypeBoxes_|. Used as an onclick handler for each data type checkbox.
    381      * @private
    382      */
    383     handleDataTypeClick_: function() {
    384       dataTypeBoxes_[this.id] = this.checked;
    385       chrome.send('coreOptionsUserMetricsAction',
    386                   ['Options_SyncToggleDataType']);
    387     },
    388 
    389     setEncryptionRadios_: function(args) {
    390       if (!args.encryptAllData && !args.usePassphrase) {
    391         $('basic-encryption-option').checked = true;
    392       } else {
    393         $('full-encryption-option').checked = true;
    394         $('full-encryption-option').disabled = true;
    395         $('basic-encryption-option').disabled = true;
    396       }
    397     },
    398 
    399     setCheckboxesAndErrors_: function(args) {
    400       this.setChooseDataTypesCheckboxes_(args);
    401       this.setEncryptionRadios_(args);
    402     },
    403 
    404     showConfigure_: function(args) {
    405       var datatypeSelect = $('sync-select-datatypes');
    406       var self = this;
    407 
    408       // Cache the sync config args so they can be reused when we transition
    409       // between the drop-down menu items in the advanced settings dialog.
    410       if (args)
    411         this.syncConfigureArgs_ = args;
    412 
    413       // Required in order to determine whether to give focus to the OK button
    414       // or passphrase field. See crbug.com/310555 and crbug.com/306353.
    415       this.confirmPageVisible_ = false;
    416       this.customizePageVisible_ = false;
    417 
    418       // Once the advanced sync settings dialog is visible, we transition
    419       // between its drop-down menu items as follows:
    420       // "Sync everything": Show encryption and passphrase sections, and disable
    421       // and check all data type checkboxes.
    422       // "Sync nothing": Hide encryption and passphrase sections, and disable
    423       // and uncheck all data type checkboxes.
    424       // "Choose what to sync": Show encryption and passphrase sections, enable
    425       // data type checkboxes, and restore their checked state to the last time
    426       // the "Choose what to sync" was selected while the dialog was still up.
    427       datatypeSelect.onchange = function() {
    428         if (this.selectedIndex == DataTypeSelection.SYNC_NOTHING) {
    429           self.showSyncNothingPage_();
    430         } else {
    431           self.showCustomizePage_(self.syncConfigureArgs_, this.selectedIndex);
    432           if (this.selectedIndex == DataTypeSelection.SYNC_EVERYTHING)
    433             self.checkAllDataTypeCheckboxes_(true);
    434           else
    435             self.restoreDataTypeCheckboxes_();
    436         }
    437       };
    438 
    439       this.resetPage_('sync-setup-configure');
    440       $('sync-setup-configure').hidden = false;
    441 
    442       // onsubmit is changed when submitting a passphrase. Reset it to its
    443       // default.
    444       $('choose-data-types-form').onsubmit = function() {
    445         self.sendConfiguration_();
    446         return false;
    447       };
    448 
    449       if (args) {
    450         this.setCheckboxesAndErrors_(args);
    451 
    452         this.useEncryptEverything_ = args.encryptAllData;
    453 
    454         // Determine whether to display the 'OK, sync everything' confirmation
    455         // dialog or the advanced sync settings dialog, and assign focus to the
    456         // OK button, or to the passphrase field if a passphrase is required.
    457         this.usePassphrase_ = args.usePassphrase;
    458         if (args.showSyncEverythingPage == false || this.usePassphrase_ ||
    459             args.syncAllDataTypes == false || args.showPassphrase) {
    460           var index = args.syncAllDataTypes ?
    461                           DataTypeSelection.SYNC_EVERYTHING :
    462                           DataTypeSelection.CHOOSE_WHAT_TO_SYNC;
    463           this.showCustomizePage_(args, index);
    464         } else {
    465           this.showSyncEverythingPage_();
    466         }
    467       }
    468     },
    469 
    470     showSpinner_: function() {
    471       this.resetPage_('sync-setup-spinner');
    472       $('sync-setup-spinner').hidden = false;
    473     },
    474 
    475     showTimeoutPage_: function() {
    476       this.resetPage_('sync-setup-timeout');
    477       $('sync-setup-timeout').hidden = false;
    478     },
    479 
    480     showSyncEverythingPage_: function() {
    481       chrome.send('coreOptionsUserMetricsAction',
    482                   ['Options_SyncSetDefault']);
    483 
    484       // Determine whether to bring the OK button into focus.
    485       var wasConfirmPageHidden = !this.confirmPageVisible_;
    486       this.confirmPageVisible_ = true;
    487       this.customizePageVisible_ = false;
    488 
    489       $('confirm-sync-preferences').hidden = false;
    490       $('customize-sync-preferences').hidden = true;
    491 
    492       // Reset the selection to 'Sync everything'.
    493       $('sync-select-datatypes').selectedIndex = 0;
    494 
    495       // The default state is to sync everything.
    496       this.setDataTypeCheckboxes_(DataTypeSelection.SYNC_EVERYTHING);
    497 
    498       if (!this.usePassphrase_)
    499         $('sync-custom-passphrase').hidden = true;
    500 
    501       if (!this.useEncryptEverything_ && !this.usePassphrase_)
    502         $('basic-encryption-option').checked = true;
    503 
    504       // Give the OK button focus only when the dialog wasn't already visible.
    505       if (wasConfirmPageHidden)
    506         $('confirm-everything-ok').focus();
    507     },
    508 
    509     /**
    510      * Reveals the UI for when the user chooses not to sync any data types.
    511      * This happens when the user signs in and selects "Sync nothing" in the
    512      * advanced sync settings dialog.
    513      * @private
    514      */
    515     showSyncNothingPage_: function() {
    516       // Reset the selection to 'Sync nothing'.
    517       $('sync-select-datatypes').selectedIndex = DataTypeSelection.SYNC_NOTHING;
    518 
    519       // Uncheck and disable the individual data type checkboxes.
    520       this.checkAllDataTypeCheckboxes_(false);
    521       this.setDataTypeCheckboxesEnabled_(false);
    522 
    523       // Hide the encryption section.
    524       $('customize-sync-encryption-new').hidden = true;
    525       $('sync-custom-passphrase-container').hidden = true;
    526       $('sync-existing-passphrase-container').hidden = true;
    527 
    528       // Hide the "use default settings" link.
    529       $('use-default-link').hidden = true;
    530       $('use-default-link').disabled = true;
    531       $('use-default-link').onclick = null;
    532     },
    533 
    534     /**
    535      * Reveals the UI for entering a custom passphrase during initial setup.
    536      * This happens if the user has previously enabled a custom passphrase on a
    537      * different machine.
    538      * @param {Array} args The args that contain the passphrase UI
    539      *     configuration.
    540      * @private
    541      */
    542     showPassphraseContainer_: function(args) {
    543       // Once we require a passphrase, we prevent the user from returning to
    544       // the Sync Everything pane.
    545       $('use-default-link').hidden = true;
    546       $('use-default-link').disabled = true;
    547       $('use-default-link').onclick = null;
    548       $('sync-custom-passphrase-container').hidden = true;
    549       $('sync-existing-passphrase-container').hidden = false;
    550 
    551       // Hide the selection options within the new encryption section when
    552       // prompting for a passphrase.
    553       $('sync-new-encryption-section-container').hidden = true;
    554 
    555       $('normal-body').hidden = true;
    556       $('google-passphrase-needed-body').hidden = true;
    557       // Display the correct prompt to the user depending on what type of
    558       // passphrase is needed.
    559       if (args.usePassphrase)
    560         $('normal-body').hidden = false;
    561       else
    562         $('google-passphrase-needed-body').hidden = false;
    563 
    564       $('passphrase-learn-more').hidden = false;
    565       // Warn the user about their incorrect passphrase if we need a passphrase
    566       // and the passphrase field is non-empty (meaning they tried to set it
    567       // previously but failed).
    568       $('incorrect-passphrase').hidden =
    569           !(args.usePassphrase && args.passphraseFailed);
    570 
    571       $('sync-passphrase-warning').hidden = false;
    572     },
    573 
    574     /**
    575      * Displays the advanced sync setting dialog, and pre-selects either the
    576      * "Sync everything" or the "Choose what to sync" drop-down menu item.
    577      * @param {cr.DataTypeSelection} index Index of item to pre-select.
    578      * @private
    579      */
    580     showCustomizePage_: function(args, index) {
    581       // Determine whether to bring the OK button field into focus.
    582       var wasCustomizePageHidden = !this.customizePageVisible_;
    583       this.customizePageVisible_ = true;
    584       this.confirmPageVisible_ = false;
    585 
    586       $('confirm-sync-preferences').hidden = true;
    587       $('customize-sync-preferences').hidden = false;
    588 
    589       $('sync-custom-passphrase-container').hidden = false;
    590       $('sync-new-encryption-section-container').hidden = false;
    591       $('customize-sync-encryption-new').hidden = false;
    592 
    593       $('sync-existing-passphrase-container').hidden = true;
    594 
    595       $('sync-select-datatypes').selectedIndex = index;
    596       this.setDataTypeCheckboxesEnabled_(
    597           index == DataTypeSelection.CHOOSE_WHAT_TO_SYNC);
    598 
    599       // Give the OK button focus only when the dialog wasn't already visible.
    600       if (wasCustomizePageHidden)
    601         $('choose-datatypes-ok').focus();
    602 
    603       if (args && args.showPassphrase) {
    604         this.showPassphraseContainer_(args);
    605         // Give the passphrase field focus only when the dialog wasn't already
    606         // visible.
    607         if (wasCustomizePageHidden)
    608           $('passphrase').focus();
    609       } else {
    610         // We only show the 'Use Default' link if we're not prompting for an
    611         // existing passphrase.
    612         $('use-default-link').hidden = false;
    613         $('use-default-link').disabled = false;
    614         $('use-default-link').onclick = function() {
    615           SyncSetupOverlay.showSyncEverythingPage();
    616           return false;
    617         };
    618       }
    619     },
    620 
    621     /**
    622      * Shows the appropriate sync setup page.
    623      * @param {string} page A page of the sync setup to show.
    624      * @param {object} args Data from the C++ to forward on to the right
    625      *     section.
    626      */
    627     showSyncSetupPage_: function(page, args) {
    628       // If the user clicks the OK button, dismiss the dialog immediately, and
    629       // do not go through the process of hiding elements of the overlay.
    630       // See crbug.com/308873.
    631       if (page == 'done') {
    632         this.closeOverlay_();
    633         return;
    634       }
    635 
    636       this.setThrobbersVisible_(false);
    637 
    638       // Hide an existing visible overlay (ensuring the close button is not
    639       // hidden).
    640       var children = document.querySelectorAll(
    641           '#sync-setup-overlay > *:not(.close-button)');
    642       for (var i = 0; i < children.length; i++)
    643         children[i].hidden = true;
    644 
    645       this.setInputElementsDisabledState_(false);
    646 
    647       // If new passphrase bodies are present, overwrite the existing ones.
    648       if (args && args.enterPassphraseBody != undefined)
    649         $('normal-body').innerHTML = args.enterPassphraseBody;
    650       if (args && args.enterGooglePassphraseBody != undefined) {
    651         $('google-passphrase-needed-body').innerHTML =
    652             args.enterGooglePassphraseBody;
    653       }
    654       if (args && args.fullEncryptionBody != undefined)
    655         $('full-encryption-body').innerHTML = args.fullEncryptionBody;
    656 
    657       // NOTE: Because both showGaiaLogin_() and showConfigure_() change the
    658       // focus, we need to ensure that the overlay container and dialog aren't
    659       // [hidden] (as trying to focus() nodes inside of a [hidden] DOM section
    660       // doesn't work).
    661       this.showOverlay_();
    662 
    663       if (page == 'configure' || page == 'passphrase')
    664         this.showConfigure_(args);
    665       else if (page == 'spinner')
    666         this.showSpinner_();
    667       else if (page == 'timeout')
    668         this.showTimeoutPage_();
    669     },
    670 
    671     /**
    672      * Changes the visibility of throbbers on this page.
    673      * @param {boolean} visible Whether or not to set all throbber nodes
    674      *     visible.
    675      */
    676     setThrobbersVisible_: function(visible) {
    677       var throbbers = this.pageDiv.getElementsByClassName('throbber');
    678       for (var i = 0; i < throbbers.length; i++)
    679         throbbers[i].style.visibility = visible ? 'visible' : 'hidden';
    680     },
    681 
    682     /**
    683      * Reset the state of all descendant elements of a root element to their
    684      * initial state.
    685      * The initial state is specified by adding a class to the descendant
    686      * element in sync_setup_overlay.html.
    687      * @param {HTMLElement} pageElementId The root page element id.
    688      * @private
    689      */
    690     resetPage_: function(pageElementId) {
    691       var page = $(pageElementId);
    692       var forEach = function(arr, fn) {
    693         var length = arr.length;
    694         for (var i = 0; i < length; i++) {
    695           fn(arr[i]);
    696         }
    697       };
    698 
    699       forEach(page.getElementsByClassName('reset-hidden'),
    700           function(elt) { elt.hidden = true; });
    701       forEach(page.getElementsByClassName('reset-shown'),
    702           function(elt) { elt.hidden = false; });
    703       forEach(page.getElementsByClassName('reset-disabled'),
    704           function(elt) { elt.disabled = true; });
    705       forEach(page.getElementsByClassName('reset-enabled'),
    706           function(elt) { elt.disabled = false; });
    707       forEach(page.getElementsByClassName('reset-value'),
    708           function(elt) { elt.value = ''; });
    709       forEach(page.getElementsByClassName('reset-opaque'),
    710           function(elt) { elt.classList.remove('transparent'); });
    711     },
    712 
    713     /**
    714      * Displays the stop syncing dialog.
    715      * @private
    716      */
    717     showStopSyncingUI_: function() {
    718       // Hide any visible children of the overlay.
    719       var overlay = $('sync-setup-overlay');
    720       for (var i = 0; i < overlay.children.length; i++)
    721         overlay.children[i].hidden = true;
    722 
    723       // Bypass OptionsPage.navigateToPage because it will call didShowPage
    724       // which will set its own visible page, based on the flow state.
    725       this.visible = true;
    726 
    727       $('sync-setup-stop-syncing').hidden = false;
    728       $('stop-syncing-cancel').focus();
    729     },
    730 
    731     /**
    732      * Determines the appropriate page to show in the Sync Setup UI based on
    733      * the state of the Sync backend. Does nothing if the user is not signed in.
    734      * @private
    735      */
    736     showSetupUI_: function() {
    737       chrome.send('SyncSetupShowSetupUI');
    738       chrome.send('coreOptionsUserMetricsAction', ['Options_SyncShowAdvanced']);
    739     },
    740 
    741     /**
    742      * Starts the signin process for the user. Does nothing if the user is
    743      * already signed in.
    744      * @private
    745      */
    746     startSignIn_: function() {
    747       chrome.send('SyncSetupStartSignIn');
    748     },
    749 
    750     /**
    751      * Forces user to sign out of Chrome for Chrome OS.
    752      * @private
    753      */
    754     doSignOutOnAuthError_: function() {
    755       chrome.send('SyncSetupDoSignOutOnAuthError');
    756     },
    757   };
    758 
    759   // These methods are for general consumption.
    760   SyncSetupOverlay.closeOverlay = function() {
    761     SyncSetupOverlay.getInstance().closeOverlay_();
    762   };
    763 
    764   SyncSetupOverlay.showSetupUI = function() {
    765     SyncSetupOverlay.getInstance().showSetupUI_();
    766   };
    767 
    768   SyncSetupOverlay.startSignIn = function() {
    769     SyncSetupOverlay.getInstance().startSignIn_();
    770   };
    771 
    772   SyncSetupOverlay.doSignOutOnAuthError = function() {
    773     SyncSetupOverlay.getInstance().doSignOutOnAuthError_();
    774   };
    775 
    776   SyncSetupOverlay.showSyncSetupPage = function(page, args) {
    777     SyncSetupOverlay.getInstance().showSyncSetupPage_(page, args);
    778   };
    779 
    780   SyncSetupOverlay.showCustomizePage = function(args, index) {
    781     SyncSetupOverlay.getInstance().showCustomizePage_(args, index);
    782   };
    783 
    784   SyncSetupOverlay.showSyncEverythingPage = function() {
    785     SyncSetupOverlay.getInstance().showSyncEverythingPage_();
    786   };
    787 
    788   SyncSetupOverlay.showStopSyncingUI = function() {
    789     SyncSetupOverlay.getInstance().showStopSyncingUI_();
    790   };
    791 
    792   // Export
    793   return {
    794     SyncSetupOverlay: SyncSetupOverlay
    795   };
    796 });
    797