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