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