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.define('options', function() { 6 var OptionsPage = options.OptionsPage; 7 var ArrayDataModel = cr.ui.ArrayDataModel; 8 9 /** 10 * ManageProfileOverlay class 11 * Encapsulated handling of the 'Manage profile...' overlay page. 12 * @constructor 13 * @class 14 */ 15 function ManageProfileOverlay() { 16 OptionsPage.call(this, 'manageProfile', 17 loadTimeData.getString('manageProfileTabTitle'), 18 'manage-profile-overlay'); 19 }; 20 21 cr.addSingletonGetter(ManageProfileOverlay); 22 23 ManageProfileOverlay.prototype = { 24 // Inherit from OptionsPage. 25 __proto__: OptionsPage.prototype, 26 27 // Info about the currently managed/deleted profile. 28 profileInfo_: null, 29 30 // Whether the currently chosen name for a new profile was assigned 31 // automatically by choosing an avatar. Set on receiveNewProfileDefaults; 32 // cleared on first edit (in onNameChanged_). 33 profileNameIsDefault_: false, 34 35 // List of default profile names corresponding to the respective icons. 36 defaultProfileNames_: [], 37 38 // An object containing all names of existing profiles. 39 existingProfileNames_: {}, 40 41 // The currently selected icon in the icon grid. 42 iconGridSelectedURL_: null, 43 44 /** 45 * Initialize the page. 46 */ 47 initializePage: function() { 48 // Call base class implementation to start preference initialization. 49 OptionsPage.prototype.initializePage.call(this); 50 51 var self = this; 52 options.ProfilesIconGrid.decorate($('manage-profile-icon-grid')); 53 options.ProfilesIconGrid.decorate($('create-profile-icon-grid')); 54 self.registerCommonEventHandlers_('create', 55 self.submitCreateProfile_.bind(self)); 56 self.registerCommonEventHandlers_('manage', 57 self.submitManageChanges_.bind(self)); 58 59 // Override the create-profile-ok and create-* keydown handlers, to avoid 60 // closing the overlay until we finish creating the profile. 61 $('create-profile-ok').onclick = function(event) { 62 self.submitCreateProfile_(); 63 }; 64 65 $('create-profile-cancel').onclick = function(event) { 66 CreateProfileOverlay.cancelCreateProfile(); 67 }; 68 69 $('manage-profile-cancel').onclick = 70 $('disconnect-managed-profile-cancel').onclick = 71 $('delete-profile-cancel').onclick = function(event) { 72 OptionsPage.closeOverlay(); 73 }; 74 $('delete-profile-ok').onclick = function(event) { 75 OptionsPage.closeOverlay(); 76 if (BrowserOptions.getCurrentProfile().isManaged) 77 return; 78 chrome.send('deleteProfile', [self.profileInfo_.filePath]); 79 options.ManagedUserListData.resetPromise(); 80 }; 81 $('add-shortcut-button').onclick = function(event) { 82 chrome.send('addProfileShortcut', [self.profileInfo_.filePath]); 83 }; 84 $('remove-shortcut-button').onclick = function(event) { 85 chrome.send('removeProfileShortcut', [self.profileInfo_.filePath]); 86 }; 87 88 $('disconnect-managed-profile-ok').onclick = function(event) { 89 OptionsPage.closeOverlay(); 90 chrome.send('deleteProfile', 91 [BrowserOptions.getCurrentProfile().filePath]); 92 } 93 94 $('create-profile-managed-signed-in-learn-more-link').onclick = 95 function(event) { 96 OptionsPage.navigateToPage('managedUserLearnMore'); 97 return false; 98 }; 99 100 $('create-profile-managed-not-signed-in-link').onclick = function(event) { 101 // The signin process will open an overlay to configure sync, which 102 // would replace this overlay. It's smoother to close this one now. 103 // TODO(pamg): Move the sync-setup overlay to a higher layer so this one 104 // can stay open under it, after making sure that doesn't break anything 105 // else. 106 OptionsPage.closeOverlay(); 107 SyncSetupOverlay.startSignIn(); 108 }; 109 110 $('create-profile-managed-sign-in-again-link').onclick = function(event) { 111 OptionsPage.closeOverlay(); 112 SyncSetupOverlay.showSetupUI(); 113 }; 114 115 $('import-existing-managed-user-link').onclick = function(event) { 116 // Hide the import button to trigger a cursor update. The import button 117 // is shown again when the import overlay loads. TODO(akuegel): Remove 118 // this temporary fix when crbug/246304 is resolved. 119 $('import-existing-managed-user-link').hidden = true; 120 OptionsPage.navigateToPage('managedUserImport'); 121 }; 122 }, 123 124 /** @override */ 125 didShowPage: function() { 126 chrome.send('requestDefaultProfileIcons', ['manage']); 127 128 // Just ignore the manage profile dialog on Chrome OS, they use /accounts. 129 if (!cr.isChromeOS && window.location.pathname == '/manageProfile') 130 ManageProfileOverlay.getInstance().prepareForManageDialog_(); 131 132 // When editing a profile, initially hide the "add shortcut" and 133 // "remove shortcut" buttons and ask the handler which to show. It will 134 // call |receiveHasProfileShortcuts|, which will show the appropriate one. 135 $('remove-shortcut-button').hidden = true; 136 $('add-shortcut-button').hidden = true; 137 138 if (loadTimeData.getBoolean('profileShortcutsEnabled')) { 139 var profileInfo = ManageProfileOverlay.getInstance().profileInfo_; 140 chrome.send('requestHasProfileShortcuts', [profileInfo.filePath]); 141 } 142 143 var manageNameField = $('manage-profile-name'); 144 // Supervised users cannot edit their names. 145 if (manageNameField.disabled) 146 $('manage-profile-ok').focus(); 147 else 148 manageNameField.focus(); 149 150 this.profileNameIsDefault_ = false; 151 }, 152 153 /** 154 * Registers event handlers that are common between create and manage modes. 155 * @param {string} mode A label that specifies the type of dialog box which 156 * is currently being viewed (i.e. 'create' or 'manage'). 157 * @param {function()} submitFunction The function that should be called 158 * when the user chooses to submit (e.g. by clicking the OK button). 159 * @private 160 */ 161 registerCommonEventHandlers_: function(mode, submitFunction) { 162 var self = this; 163 $(mode + '-profile-icon-grid').addEventListener('change', function(e) { 164 self.onIconGridSelectionChanged_(mode); 165 }); 166 $(mode + '-profile-name').oninput = function(event) { 167 self.onNameChanged_(mode); 168 }; 169 $(mode + '-profile-ok').onclick = function(event) { 170 OptionsPage.closeOverlay(); 171 submitFunction(); 172 }; 173 }, 174 175 /** 176 * Set the profile info used in the dialog. 177 * @param {Object} profileInfo An object of the form: 178 * profileInfo = { 179 * name: "Profile Name", 180 * iconURL: "chrome://path/to/icon/image", 181 * filePath: "/path/to/profile/data/on/disk", 182 * isCurrentProfile: false, 183 * isManaged: false 184 * }; 185 * @param {string} mode A label that specifies the type of dialog box which 186 * is currently being viewed (i.e. 'create' or 'manage'). 187 * @private 188 */ 189 setProfileInfo_: function(profileInfo, mode) { 190 this.iconGridSelectedURL_ = profileInfo.iconURL; 191 this.profileInfo_ = profileInfo; 192 $(mode + '-profile-name').value = profileInfo.name; 193 $(mode + '-profile-icon-grid').selectedItem = profileInfo.iconURL; 194 }, 195 196 /** 197 * Sets the name of the profile being edited or created. 198 * @param {string} name New profile name. 199 * @param {string} mode A label that specifies the type of dialog box which 200 * is currently being viewed (i.e. 'create' or 'manage'). 201 * @private 202 */ 203 setProfileName_: function(name, mode) { 204 if (this.profileInfo_) 205 this.profileInfo_.name = name; 206 $(mode + '-profile-name').value = name; 207 }, 208 209 /** 210 * Set an array of default icon URLs. These will be added to the grid that 211 * the user will use to choose their profile icon. 212 * @param {string} mode A label that specifies the type of dialog box which 213 * is currently being viewed (i.e. 'create' or 'manage'). 214 * @param {Array.<string>} iconURLs An array of icon URLs. 215 * @param {Array.<string>} names An array of default names 216 * corresponding to the icons. 217 * @private 218 */ 219 receiveDefaultProfileIconsAndNames_: function(mode, iconURLs, names) { 220 this.defaultProfileNames_ = names; 221 222 var grid = $(mode + '-profile-icon-grid'); 223 224 grid.dataModel = new ArrayDataModel(iconURLs); 225 226 if (this.profileInfo_) 227 grid.selectedItem = this.profileInfo_.iconURL; 228 229 // Recalculate the measured item size. 230 grid.measured_ = null; 231 grid.columns = 0; 232 grid.redraw(); 233 }, 234 235 /** 236 * Callback to set the initial values when creating a new profile. 237 * @param {Object} profileInfo An object of the form: 238 * profileInfo = { 239 * name: "Profile Name", 240 * iconURL: "chrome://path/to/icon/image", 241 * }; 242 * @private 243 */ 244 receiveNewProfileDefaults_: function(profileInfo) { 245 ManageProfileOverlay.setProfileInfo(profileInfo, 'create'); 246 this.profileNameIsDefault_ = true; 247 $('create-profile-name-label').hidden = false; 248 $('create-profile-name').hidden = false; 249 // Trying to change the focus if this isn't the topmost overlay can 250 // instead cause the FocusManager to override another overlay's focus, 251 // e.g. if an overlay above this one is in the process of being reloaded. 252 // But the C++ handler calls this method directly on ManageProfileOverlay, 253 // so check the pageDiv to also include its subclasses (in particular 254 // CreateProfileOverlay, which has higher sub-overlays). 255 if (OptionsPage.getTopmostVisiblePage().pageDiv == this.pageDiv) { 256 // This will only have an effect if the 'create-profile-name' element 257 // is visible, i.e. if the overlay is in create mode. 258 $('create-profile-name').focus(); 259 } 260 $('create-profile-ok').disabled = false; 261 }, 262 263 /** 264 * Set a dictionary of all profile names. These are used to prevent the 265 * user from naming two profiles the same. 266 * @param {Object} profileNames A dictionary of profile names. 267 * @private 268 */ 269 receiveExistingProfileNames_: function(profileNames) { 270 this.existingProfileNames_ = profileNames; 271 }, 272 273 /** 274 * Callback to show the add/remove shortcut buttons when in edit mode, 275 * called by the handler as a result of the 'requestHasProfileShortcuts_' 276 * message. 277 * @param {boolean} hasShortcuts Whether profile has any existing shortcuts. 278 * @private 279 */ 280 receiveHasProfileShortcuts_: function(hasShortcuts) { 281 $('add-shortcut-button').hidden = hasShortcuts; 282 $('remove-shortcut-button').hidden = !hasShortcuts; 283 }, 284 285 /** 286 * Display the error bubble, with |errorHtml| in the bubble. 287 * @param {string} errorHtml The html string to display as an error. 288 * @param {string} mode A label that specifies the type of dialog box which 289 * is currently being viewed (i.e. 'create' or 'manage'). 290 * @param {boolean} disableOKButton True if the dialog's OK button should be 291 * disabled when the error bubble is shown. It will be (re-)enabled when 292 * the error bubble is hidden. 293 * @private 294 */ 295 showErrorBubble_: function(errorHtml, mode, disableOKButton) { 296 var nameErrorEl = $(mode + '-profile-error-bubble'); 297 nameErrorEl.hidden = false; 298 nameErrorEl.innerHTML = errorHtml; 299 300 if (disableOKButton) 301 $(mode + '-profile-ok').disabled = true; 302 }, 303 304 /** 305 * Hide the error bubble. 306 * @param {string} mode A label that specifies the type of dialog box which 307 * is currently being viewed (i.e. 'create' or 'manage'). 308 * @private 309 */ 310 hideErrorBubble_: function(mode) { 311 $(mode + '-profile-error-bubble').innerHTML = ''; 312 $(mode + '-profile-error-bubble').hidden = true; 313 $(mode + '-profile-ok').disabled = false; 314 }, 315 316 /** 317 * oninput callback for <input> field. 318 * @param {string} mode A label that specifies the type of dialog box which 319 * is currently being viewed (i.e. 'create' or 'manage'). 320 * @private 321 */ 322 onNameChanged_: function(mode) { 323 this.profileNameIsDefault_ = false; 324 this.updateCreateOrImport_(mode); 325 }, 326 327 /** 328 * Called when the profile name is changed or the 'create managed' checkbox 329 * is toggled. Updates the 'ok' button and the 'import existing supervised 330 * user' link. 331 * @param {string} mode A label that specifies the type of dialog box which 332 * is currently being viewed (i.e. 'create' or 'manage'). 333 * @private 334 */ 335 updateCreateOrImport_: function(mode) { 336 // In 'create' mode, check for existing managed users with the same name. 337 if (mode == 'create' && $('create-profile-managed').checked) { 338 options.ManagedUserListData.requestExistingManagedUsers().then( 339 this.receiveExistingManagedUsers_.bind(this), 340 this.onSigninError_.bind(this)); 341 } else { 342 this.updateOkButton_(mode); 343 } 344 }, 345 346 /** 347 * Callback which receives the list of existing managed users. Checks if the 348 * currently entered name is the name of an already existing managed user. 349 * If yes, the user is prompted to import the existing managed user, and the 350 * create button is disabled. 351 * @param {Array.<Object>} The list of existing managed users. 352 * @private 353 */ 354 receiveExistingManagedUsers_: function(managedUsers) { 355 var newName = $('create-profile-name').value; 356 var i; 357 for (i = 0; i < managedUsers.length; ++i) { 358 if (managedUsers[i].name == newName && 359 !managedUsers[i].onCurrentDevice) { 360 var errorHtml = loadTimeData.getStringF( 361 'manageProfilesExistingSupervisedUser', 362 HTMLEscape(elide(newName, /* maxLength */ 50))); 363 this.showErrorBubble_(errorHtml, 'create', true); 364 365 // Check if another supervised user also exists with that name. 366 var nameIsUnique = true; 367 var j; 368 for (j = i + 1; j < managedUsers.length; ++j) { 369 if (managedUsers[j].name == newName) { 370 nameIsUnique = false; 371 break; 372 } 373 } 374 var self = this; 375 function getImportHandler(managedUser, nameIsUnique) { 376 return function() { 377 if (managedUser.needAvatar || !nameIsUnique) { 378 OptionsPage.navigateToPage('managedUserImport'); 379 } else { 380 self.hideErrorBubble_('create'); 381 CreateProfileOverlay.updateCreateInProgress(true); 382 chrome.send('createProfile', 383 [managedUser.name, managedUser.iconURL, false, true, 384 managedUser.id]); 385 } 386 } 387 }; 388 $('supervised-user-import').onclick = 389 getImportHandler(managedUsers[i], nameIsUnique); 390 $('create-profile-ok').disabled = true; 391 return; 392 } 393 } 394 this.updateOkButton_('create'); 395 }, 396 397 /** 398 * Called in case the request for the list of managed users fails because of 399 * a signin error. 400 * @private 401 */ 402 onSigninError_: function() { 403 this.updateImportExistingManagedUserLink_(false); 404 }, 405 406 /** 407 * Called to update the state of the ok button depending if the name is 408 * already used or not. 409 * @param {string} mode A label that specifies the type of dialog box which 410 * is currently being viewed (i.e. 'create' or 'manage'). 411 * @private 412 */ 413 updateOkButton_: function(mode) { 414 var oldName = this.profileInfo_.name; 415 var newName = $(mode + '-profile-name').value; 416 var nameIsDuplicate = this.existingProfileNames_[newName] != undefined; 417 if (mode == 'manage' && oldName == newName) 418 nameIsDuplicate = false; 419 if (nameIsDuplicate) { 420 var errorHtml = 421 loadTimeData.getString('manageProfilesDuplicateNameError'); 422 this.showErrorBubble_(errorHtml, mode, true); 423 } else { 424 this.hideErrorBubble_(mode); 425 426 var nameIsValid = $(mode + '-profile-name').validity.valid; 427 $(mode + '-profile-ok').disabled = !nameIsValid; 428 } 429 }, 430 431 /** 432 * Called when the user clicks "OK" or hits enter. Saves the newly changed 433 * profile info. 434 * @private 435 */ 436 submitManageChanges_: function() { 437 var name = $('manage-profile-name').value; 438 var iconURL = $('manage-profile-icon-grid').selectedItem; 439 440 chrome.send('setProfileIconAndName', 441 [this.profileInfo_.filePath, iconURL, name]); 442 if (name != this.profileInfo_.name) 443 options.ManagedUserListData.resetPromise(); 444 }, 445 446 /** 447 * Called when the user clicks "OK" or hits enter. Creates the profile 448 * using the information in the dialog. 449 * @private 450 */ 451 submitCreateProfile_: function() { 452 // This is visual polish: the UI to access this should be disabled for 453 // managed users, and the back end will prevent user creation anyway. 454 if (this.profileInfo_ && this.profileInfo_.isManaged) 455 return; 456 457 this.hideErrorBubble_('create'); 458 CreateProfileOverlay.updateCreateInProgress(true); 459 460 // Get the user's chosen name and icon, or default if they do not 461 // wish to customize their profile. 462 var name = $('create-profile-name').value; 463 var iconUrl = $('create-profile-icon-grid').selectedItem; 464 var createShortcut = $('create-shortcut').checked; 465 var isManaged = $('create-profile-managed').checked; 466 var existingManagedUserId = ''; 467 468 // 'createProfile' is handled by the CreateProfileHandler. 469 chrome.send('createProfile', 470 [name, iconUrl, createShortcut, 471 isManaged, existingManagedUserId]); 472 }, 473 474 /** 475 * Called when the selected icon in the icon grid changes. 476 * @param {string} mode A label that specifies the type of dialog box which 477 * is currently being viewed (i.e. 'create' or 'manage'). 478 * @private 479 */ 480 onIconGridSelectionChanged_: function(mode) { 481 var iconURL = $(mode + '-profile-icon-grid').selectedItem; 482 if (!iconURL || iconURL == this.iconGridSelectedURL_) 483 return; 484 this.iconGridSelectedURL_ = iconURL; 485 if (this.profileNameIsDefault_) { 486 var index = $(mode + '-profile-icon-grid').selectionModel.selectedIndex; 487 var name = this.defaultProfileNames_[index]; 488 if (name) { 489 this.setProfileName_(name, mode); 490 } 491 } 492 if (this.profileInfo_ && this.profileInfo_.filePath) { 493 chrome.send('profileIconSelectionChanged', 494 [this.profileInfo_.filePath, iconURL]); 495 } 496 }, 497 498 /** 499 * Updates the contents of the "Manage Profile" section of the dialog, 500 * and shows that section. 501 * @private 502 */ 503 prepareForManageDialog_: function() { 504 chrome.send('refreshGaiaPicture'); 505 var profileInfo = BrowserOptions.getCurrentProfile(); 506 ManageProfileOverlay.setProfileInfo(profileInfo, 'manage'); 507 $('manage-profile-overlay-create').hidden = true; 508 $('manage-profile-overlay-manage').hidden = false; 509 $('manage-profile-overlay-delete').hidden = true; 510 $('manage-profile-overlay-disconnect-managed').hidden = true; 511 $('manage-profile-name').disabled = profileInfo.isManaged; 512 this.hideErrorBubble_('manage'); 513 }, 514 515 /** 516 * Display the "Manage Profile" dialog. 517 * @private 518 */ 519 showManageDialog_: function() { 520 this.prepareForManageDialog_(); 521 OptionsPage.navigateToPage('manageProfile'); 522 }, 523 524 /** 525 * Display the "Delete Profile" dialog. 526 * @param {Object} profileInfo The profile object of the profile to delete. 527 * @private 528 */ 529 showDeleteDialog_: function(profileInfo) { 530 if (BrowserOptions.getCurrentProfile().isManaged) 531 return; 532 533 ManageProfileOverlay.setProfileInfo(profileInfo, 'manage'); 534 $('manage-profile-overlay-create').hidden = true; 535 $('manage-profile-overlay-manage').hidden = true; 536 $('manage-profile-overlay-delete').hidden = false; 537 $('manage-profile-overlay-disconnect-managed').hidden = true; 538 $('delete-profile-icon').style.content = 539 getProfileAvatarIcon(profileInfo.iconURL); 540 $('delete-profile-text').textContent = 541 loadTimeData.getStringF('deleteProfileMessage', 542 elide(profileInfo.name, /* maxLength */ 50)); 543 $('delete-managed-profile-addendum').hidden = !profileInfo.isManaged; 544 545 // Because this dialog isn't useful when refreshing or as part of the 546 // history, don't create a history entry for it when showing. 547 OptionsPage.showPageByName('manageProfile', false); 548 }, 549 550 /** 551 * Display the "Disconnect Managed Profile" dialog. 552 * @private 553 */ 554 showDisconnectManagedProfileDialog_: function(replacements) { 555 loadTimeData.overrideValues(replacements); 556 $('manage-profile-overlay-create').hidden = true; 557 $('manage-profile-overlay-manage').hidden = true; 558 $('manage-profile-overlay-delete').hidden = true; 559 $('disconnect-managed-profile-domain-information').innerHTML = 560 loadTimeData.getString('disconnectManagedProfileDomainInformation'); 561 $('disconnect-managed-profile-text').innerHTML = 562 loadTimeData.getString('disconnectManagedProfileText'); 563 $('manage-profile-overlay-disconnect-managed').hidden = false; 564 565 // Because this dialog isn't useful when refreshing or as part of the 566 // history, don't create a history entry for it when showing. 567 OptionsPage.showPageByName('manageProfile', false); 568 }, 569 570 /** 571 * Display the "Create Profile" dialog. 572 * @private 573 */ 574 showCreateDialog_: function() { 575 OptionsPage.navigateToPage('createProfile'); 576 }, 577 }; 578 579 // Forward public APIs to private implementations. 580 [ 581 'receiveDefaultProfileIconsAndNames', 582 'receiveNewProfileDefaults', 583 'receiveExistingProfileNames', 584 'receiveHasProfileShortcuts', 585 'setProfileInfo', 586 'setProfileName', 587 'showManageDialog', 588 'showDeleteDialog', 589 'showDisconnectManagedProfileDialog', 590 'showCreateDialog', 591 ].forEach(function(name) { 592 ManageProfileOverlay[name] = function() { 593 var instance = ManageProfileOverlay.getInstance(); 594 return instance[name + '_'].apply(instance, arguments); 595 }; 596 }); 597 598 function CreateProfileOverlay() { 599 OptionsPage.call(this, 'createProfile', 600 loadTimeData.getString('createProfileTabTitle'), 601 'manage-profile-overlay'); 602 }; 603 604 cr.addSingletonGetter(CreateProfileOverlay); 605 606 CreateProfileOverlay.prototype = { 607 // Inherit from ManageProfileOverlay. 608 __proto__: ManageProfileOverlay.prototype, 609 610 // The signed-in email address of the current profile, or empty if they're 611 // not signed in. 612 signedInEmail_: '', 613 614 /** @override */ 615 canShowPage: function() { 616 return !BrowserOptions.getCurrentProfile().isManaged; 617 }, 618 619 /** 620 * Configures the overlay to the "create user" mode. 621 * @override 622 */ 623 didShowPage: function() { 624 chrome.send('requestCreateProfileUpdate'); 625 chrome.send('requestDefaultProfileIcons', ['create']); 626 chrome.send('requestNewProfileDefaults'); 627 628 $('manage-profile-overlay-create').hidden = false; 629 $('manage-profile-overlay-manage').hidden = true; 630 $('manage-profile-overlay-delete').hidden = true; 631 $('manage-profile-overlay-disconnect-managed').hidden = true; 632 $('create-profile-instructions').textContent = 633 loadTimeData.getStringF('createProfileInstructions'); 634 this.hideErrorBubble_(); 635 this.updateCreateInProgress_(false); 636 637 var shortcutsEnabled = loadTimeData.getBoolean('profileShortcutsEnabled'); 638 $('create-shortcut-container').hidden = !shortcutsEnabled; 639 $('create-shortcut').checked = shortcutsEnabled; 640 641 $('create-profile-name-label').hidden = true; 642 $('create-profile-name').hidden = true; 643 $('create-profile-ok').disabled = true; 644 645 $('create-profile-managed').checked = false; 646 $('import-existing-managed-user-link').hidden = true; 647 $('create-profile-managed').onchange = function() { 648 ManageProfileOverlay.getInstance().updateCreateOrImport_('create'); 649 }; 650 $('create-profile-managed-signed-in').disabled = true; 651 $('create-profile-managed-signed-in').hidden = true; 652 $('create-profile-managed-not-signed-in').hidden = true; 653 654 this.profileNameIsDefault_ = false; 655 }, 656 657 /** @override */ 658 handleCancel: function() { 659 this.cancelCreateProfile_(); 660 }, 661 662 /** @override */ 663 showErrorBubble_: function(errorHtml) { 664 ManageProfileOverlay.getInstance().showErrorBubble_(errorHtml, 665 'create', 666 false); 667 }, 668 669 /** @override */ 670 hideErrorBubble_: function() { 671 ManageProfileOverlay.getInstance().hideErrorBubble_('create'); 672 }, 673 674 /** 675 * Updates the UI when a profile create step begins or ends. 676 * Note that hideErrorBubble_() also enables the "OK" button, so it 677 * must be called before this function if both are used. 678 * @param {boolean} inProgress True if the UI should be updated to show that 679 * profile creation is now in progress. 680 * @private 681 */ 682 updateCreateInProgress_: function(inProgress) { 683 this.createInProgress_ = inProgress; 684 this.updateCreateManagedUserCheckbox_(); 685 686 $('create-profile-icon-grid').disabled = inProgress; 687 $('create-profile-name').disabled = inProgress; 688 $('create-shortcut').disabled = inProgress; 689 $('create-profile-ok').disabled = inProgress; 690 $('import-existing-managed-user-link').disabled = inProgress; 691 692 $('create-profile-throbber').hidden = !inProgress; 693 }, 694 695 /** 696 * Cancels the creation of the a profile. It is safe to call this even 697 * when no profile is in the process of being created. 698 * @private 699 */ 700 cancelCreateProfile_: function() { 701 OptionsPage.closeOverlay(); 702 chrome.send('cancelCreateProfile'); 703 this.hideErrorBubble_(); 704 this.updateCreateInProgress_(false); 705 }, 706 707 /** 708 * Shows an error message describing an error that occurred while creating 709 * a new profile. 710 * Called by BrowserOptions via the BrowserOptionsHandler. 711 * @param {string} error The error message to display. 712 * @private 713 */ 714 onError_: function(error) { 715 this.updateCreateInProgress_(false); 716 this.showErrorBubble_(error); 717 }, 718 719 /** 720 * Shows a warning message giving information while creating a new profile. 721 * Called by BrowserOptions via the BrowserOptionsHandler. 722 * @param {string} warning The warning message to display. 723 * @private 724 */ 725 onWarning_: function(warning) { 726 this.showErrorBubble_(warning); 727 }, 728 729 /** 730 * For new supervised users, shows a confirmation page after successfully 731 * creating a new profile; otherwise, the handler will open a new window. 732 * @param {Object} profileInfo An object of the form: 733 * profileInfo = { 734 * name: "Profile Name", 735 * filePath: "/path/to/profile/data/on/disk" 736 * isManaged: (true|false), 737 * }; 738 * @private 739 */ 740 onSuccess_: function(profileInfo) { 741 this.updateCreateInProgress_(false); 742 OptionsPage.closeOverlay(); 743 if (profileInfo.isManaged) { 744 options.ManagedUserListData.resetPromise(); 745 profileInfo.custodianEmail = this.signedInEmail_; 746 ManagedUserCreateConfirmOverlay.setProfileInfo(profileInfo); 747 OptionsPage.showPageByName('managedUserCreateConfirm', false); 748 BrowserOptions.updateManagesSupervisedUsers(true); 749 } 750 }, 751 752 /** 753 * Updates the signed-in or not-signed-in UI when in create mode. Called by 754 * the handler in response to the 'requestCreateProfileUpdate' message. 755 * updateManagedUsersAllowed_ is expected to be called after this is, and 756 * will update additional UI elements. 757 * @param {string} email The email address of the currently signed-in user. 758 * An empty string indicates that the user is not signed in. 759 * @param {boolean} hasError Whether the user's sign-in credentials are 760 * still valid. 761 * @private 762 */ 763 updateSignedInStatus_: function(email, hasError) { 764 this.signedInEmail_ = email; 765 this.hasError_ = hasError; 766 var isSignedIn = email !== ''; 767 $('create-profile-managed-signed-in').hidden = !isSignedIn; 768 $('create-profile-managed-not-signed-in').hidden = isSignedIn; 769 770 if (isSignedIn) { 771 var accountDetailsOutOfDate = 772 $('create-profile-managed-account-details-out-of-date-label'); 773 accountDetailsOutOfDate.textContent = loadTimeData.getStringF( 774 'manageProfilesManagedAccountDetailsOutOfDate', email); 775 accountDetailsOutOfDate.hidden = !hasError; 776 777 $('create-profile-managed-signed-in-label').textContent = 778 loadTimeData.getStringF( 779 'manageProfilesManagedSignedInLabel', email); 780 $('create-profile-managed-signed-in-label').hidden = hasError; 781 782 $('create-profile-managed-sign-in-again-link').hidden = !hasError; 783 $('create-profile-managed-signed-in-learn-more-link').hidden = hasError; 784 } 785 786 this.updateImportExistingManagedUserLink_(isSignedIn && !hasError); 787 }, 788 789 /** 790 * Enables/disables the 'import existing managed users' link button. 791 * It also updates the button text. 792 * @param {boolean} enable True to enable the link button and 793 * false otherwise. 794 * @private 795 */ 796 updateImportExistingManagedUserLink_: function(enable) { 797 var importManagedUserElement = $('import-existing-managed-user-link'); 798 importManagedUserElement.hidden = false; 799 importManagedUserElement.disabled = !enable || this.createInProgress_; 800 importManagedUserElement.textContent = enable ? 801 loadTimeData.getString('importExistingManagedUserLink') : 802 loadTimeData.getString('signInToImportManagedUsers'); 803 }, 804 805 /** 806 * Sets whether creating managed users is allowed or not. Called by the 807 * handler in response to the 'requestCreateProfileUpdate' message or a 808 * change in the (policy-controlled) pref that prohibits creating managed 809 * users, after the signed-in status has been updated. 810 * @param {boolean} allowed True if creating managed users should be 811 * allowed. 812 * @private 813 */ 814 updateManagedUsersAllowed_: function(allowed) { 815 this.managedUsersAllowed_ = allowed; 816 this.updateCreateManagedUserCheckbox_(); 817 818 $('create-profile-managed-not-signed-in-link').hidden = !allowed; 819 if (!allowed) { 820 $('create-profile-managed-indicator').setAttribute('controlled-by', 821 'policy'); 822 } else { 823 $('create-profile-managed-indicator').removeAttribute('controlled-by'); 824 } 825 }, 826 827 /** 828 * Updates the status of the "create managed user" checkbox. Called from 829 * updateManagedUsersAllowed_() or updateCreateInProgress_(). 830 * updateSignedInStatus_() does not call this method directly, because it 831 * will be followed by a call to updateManagedUsersAllowed_(). 832 * @private 833 */ 834 updateCreateManagedUserCheckbox_: function() { 835 $('create-profile-managed').disabled = 836 !this.managedUsersAllowed_ || this.createInProgress_ || 837 this.signedInEmail_ == '' || this.hasError_; 838 }, 839 }; 840 841 // Forward public APIs to private implementations. 842 [ 843 'cancelCreateProfile', 844 'onError', 845 'onSuccess', 846 'onWarning', 847 'updateCreateInProgress', 848 'updateManagedUsersAllowed', 849 'updateSignedInStatus', 850 ].forEach(function(name) { 851 CreateProfileOverlay[name] = function() { 852 var instance = CreateProfileOverlay.getInstance(); 853 return instance[name + '_'].apply(instance, arguments); 854 }; 855 }); 856 857 // Export 858 return { 859 ManageProfileOverlay: ManageProfileOverlay, 860 CreateProfileOverlay: CreateProfileOverlay, 861 }; 862}); 863