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 var Page = cr.ui.pageManager.Page; 7 var PageManager = cr.ui.pageManager.PageManager; 8 var ArrayDataModel = cr.ui.ArrayDataModel; 9 10 /** 11 * ManageProfileOverlay class 12 * Encapsulated handling of the 'Manage profile...' overlay page. 13 * @constructor 14 * @extends {cr.ui.pageManager.Page} 15 */ 16 function ManageProfileOverlay() { 17 Page.call(this, 'manageProfile', 18 loadTimeData.getString('manageProfileTabTitle'), 19 'manage-profile-overlay'); 20 }; 21 22 cr.addSingletonGetter(ManageProfileOverlay); 23 24 ManageProfileOverlay.prototype = { 25 // Inherit from Page. 26 __proto__: Page.prototype, 27 28 // Info about the currently managed/deleted profile. 29 profileInfo_: null, 30 31 // Whether the currently chosen name for a new profile was assigned 32 // automatically by choosing an avatar. Set on receiveNewProfileDefaults; 33 // cleared on first edit (in onNameChanged_). 34 profileNameIsDefault_: false, 35 36 // List of default profile names corresponding to the respective icons. 37 defaultProfileNames_: [], 38 39 // An object containing all names of existing profiles. 40 existingProfileNames_: {}, 41 42 // The currently selected icon in the icon grid. 43 iconGridSelectedURL_: null, 44 45 /** @override */ 46 initializePage: function() { 47 Page.prototype.initializePage.call(this); 48 49 var self = this; 50 options.ProfilesIconGrid.decorate($('manage-profile-icon-grid')); 51 options.ProfilesIconGrid.decorate($('create-profile-icon-grid')); 52 self.registerCommonEventHandlers_('create', 53 self.submitCreateProfile_.bind(self)); 54 self.registerCommonEventHandlers_('manage', 55 self.submitManageChanges_.bind(self)); 56 57 // Override the create-profile-ok and create-* keydown handlers, to avoid 58 // closing the overlay until we finish creating the profile. 59 $('create-profile-ok').onclick = function(event) { 60 self.submitCreateProfile_(); 61 }; 62 63 $('create-profile-cancel').onclick = function(event) { 64 CreateProfileOverlay.cancelCreateProfile(); 65 }; 66 67 $('manage-profile-cancel').onclick = 68 $('disconnect-managed-profile-cancel').onclick = 69 $('delete-profile-cancel').onclick = function(event) { 70 PageManager.closeOverlay(); 71 }; 72 $('delete-profile-ok').onclick = function(event) { 73 PageManager.closeOverlay(); 74 if (BrowserOptions.getCurrentProfile().isSupervised) 75 return; 76 chrome.send('deleteProfile', [self.profileInfo_.filePath]); 77 options.SupervisedUserListData.resetPromise(); 78 }; 79 $('add-shortcut-button').onclick = function(event) { 80 chrome.send('addProfileShortcut', [self.profileInfo_.filePath]); 81 }; 82 $('remove-shortcut-button').onclick = function(event) { 83 chrome.send('removeProfileShortcut', [self.profileInfo_.filePath]); 84 }; 85 86 $('disconnect-managed-profile-ok').onclick = function(event) { 87 PageManager.closeOverlay(); 88 chrome.send('deleteProfile', 89 [BrowserOptions.getCurrentProfile().filePath]); 90 }; 91 92 $('create-profile-supervised-signed-in-learn-more-link').onclick = 93 function(event) { 94 PageManager.showPageByName('supervisedUserLearnMore'); 95 return false; 96 }; 97 98 $('create-profile-supervised-sign-in-link').onclick = 99 function(event) { 100 // The signin process will open an overlay to configure sync, which 101 // would replace this overlay. It's smoother to close this one now. 102 // TODO(pamg): Move the sync-setup overlay to a higher layer so this one 103 // can stay open under it, after making sure that doesn't break anything 104 // else. 105 PageManager.closeOverlay(); 106 SyncSetupOverlay.startSignIn(); 107 }; 108 109 $('create-profile-supervised-sign-in-again-link').onclick = 110 function(event) { 111 PageManager.closeOverlay(); 112 SyncSetupOverlay.showSetupUI(); 113 }; 114 115 $('import-existing-supervised-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-supervised-user-link').hidden = true; 120 PageManager.showPageByName('supervisedUserImport'); 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 PageManager.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 * isSupervised: 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 (PageManager.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 supervised' 329 * checkbox is toggled. Updates the 'ok' button and the 'import existing 330 * supervised 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 this.updateOkButton_(mode); 337 // In 'create' mode, check for existing supervised users with the same 338 // name. 339 if (mode == 'create') 340 this.requestExistingSupervisedUsers_(); 341 }, 342 343 /** 344 * Tries to get the list of existing supervised users and updates the UI 345 * accordingly. 346 * @private 347 */ 348 requestExistingSupervisedUsers_: function() { 349 options.SupervisedUserListData.requestExistingSupervisedUsers().then( 350 this.receiveExistingSupervisedUsers_.bind(this), 351 this.onSigninError_.bind(this)); 352 }, 353 354 /** 355 * @param {Object} supervisedUser 356 * @param {boolean} nameIsUnique 357 */ 358 getImportHandler_: function(supervisedUser, nameIsUnique) { 359 return function() { 360 if (supervisedUser.needAvatar || !nameIsUnique) { 361 PageManager.showPageByName('supervisedUserImport'); 362 } else { 363 this.hideErrorBubble_('create'); 364 CreateProfileOverlay.updateCreateInProgress(true); 365 chrome.send('createProfile', 366 [supervisedUser.name, supervisedUser.iconURL, false, true, 367 supervisedUser.id]); 368 } 369 }.bind(this); 370 }, 371 372 /** 373 * Callback which receives the list of existing supervised users. Checks if 374 * the currently entered name is the name of an already existing supervised 375 * user. If yes, the user is prompted to import the existing supervised 376 * user, and the create button is disabled. 377 * If the received list is empty, hides the "import" link. 378 * @param {Array.<Object>} supervisedUsers The list of existing supervised 379 * users. 380 * @private 381 */ 382 receiveExistingSupervisedUsers_: function(supervisedUsers) { 383 $('import-existing-supervised-user-link').hidden = 384 supervisedUsers.length === 0; 385 if (!$('create-profile-supervised').checked) 386 return; 387 388 var newName = $('create-profile-name').value; 389 var i; 390 for (i = 0; i < supervisedUsers.length; ++i) { 391 if (supervisedUsers[i].name == newName && 392 !supervisedUsers[i].onCurrentDevice) { 393 var errorHtml = loadTimeData.getStringF( 394 'manageProfilesExistingSupervisedUser', 395 HTMLEscape(elide(newName, /* maxLength */ 50))); 396 this.showErrorBubble_(errorHtml, 'create', true); 397 398 // Check if another supervised user also exists with that name. 399 var nameIsUnique = true; 400 var j; 401 for (j = i + 1; j < supervisedUsers.length; ++j) { 402 if (supervisedUsers[j].name == newName) { 403 nameIsUnique = false; 404 break; 405 } 406 } 407 $('supervised-user-import-existing').onclick = 408 this.getImportHandler_(supervisedUsers[i], nameIsUnique); 409 $('create-profile-ok').disabled = true; 410 return; 411 } 412 } 413 }, 414 415 /** 416 * Called in case the request for the list of supervised users fails because 417 * of a signin error. 418 * @private 419 */ 420 onSigninError_: function() { 421 this.updateSignedInStatus_(this.signedInEmail_, true); 422 }, 423 424 /** 425 * Called to update the state of the ok button depending if the name is 426 * already used or not. 427 * @param {string} mode A label that specifies the type of dialog box which 428 * is currently being viewed (i.e. 'create' or 'manage'). 429 * @private 430 */ 431 updateOkButton_: function(mode) { 432 var oldName = this.profileInfo_.name; 433 var newName = $(mode + '-profile-name').value; 434 var nameIsDuplicate = this.existingProfileNames_[newName] != undefined; 435 if (mode == 'manage' && oldName == newName) 436 nameIsDuplicate = false; 437 if (nameIsDuplicate) { 438 var errorHtml = 439 loadTimeData.getString('manageProfilesDuplicateNameError'); 440 this.showErrorBubble_(errorHtml, mode, true); 441 } else { 442 this.hideErrorBubble_(mode); 443 444 var nameIsValid = $(mode + '-profile-name').validity.valid; 445 $(mode + '-profile-ok').disabled = !nameIsValid; 446 } 447 }, 448 449 /** 450 * Called when the user clicks "OK" or hits enter. Saves the newly changed 451 * profile info. 452 * @private 453 */ 454 submitManageChanges_: function() { 455 var name = $('manage-profile-name').value; 456 var iconURL = $('manage-profile-icon-grid').selectedItem; 457 458 chrome.send('setProfileIconAndName', 459 [this.profileInfo_.filePath, iconURL, name]); 460 if (name != this.profileInfo_.name) 461 options.SupervisedUserListData.resetPromise(); 462 }, 463 464 /** @private */ 465 updateSignedInStatus_: assertNotReached, 466 467 /** 468 * Called when the user clicks "OK" or hits enter. Creates the profile 469 * using the information in the dialog. 470 * @private 471 */ 472 submitCreateProfile_: function() { 473 // This is visual polish: the UI to access this should be disabled for 474 // supervised users, and the back end will prevent user creation anyway. 475 if (this.profileInfo_ && this.profileInfo_.isSupervised) 476 return; 477 478 this.hideErrorBubble_('create'); 479 CreateProfileOverlay.updateCreateInProgress(true); 480 481 // Get the user's chosen name and icon, or default if they do not 482 // wish to customize their profile. 483 var name = $('create-profile-name').value; 484 var iconUrl = $('create-profile-icon-grid').selectedItem; 485 var createShortcut = $('create-shortcut').checked; 486 var isSupervised = $('create-profile-supervised').checked; 487 var existingSupervisedUserId = ''; 488 489 // 'createProfile' is handled by the CreateProfileHandler. 490 chrome.send('createProfile', 491 [name, iconUrl, createShortcut, 492 isSupervised, existingSupervisedUserId]); 493 }, 494 495 /** 496 * Called when the selected icon in the icon grid changes. 497 * @param {string} mode A label that specifies the type of dialog box which 498 * is currently being viewed (i.e. 'create' or 'manage'). 499 * @private 500 */ 501 onIconGridSelectionChanged_: function(mode) { 502 var iconURL = $(mode + '-profile-icon-grid').selectedItem; 503 if (!iconURL || iconURL == this.iconGridSelectedURL_) 504 return; 505 this.iconGridSelectedURL_ = iconURL; 506 if (this.profileNameIsDefault_) { 507 var index = $(mode + '-profile-icon-grid').selectionModel.selectedIndex; 508 var name = this.defaultProfileNames_[index]; 509 if (name) { 510 this.setProfileName_(name, mode); 511 this.updateCreateOrImport_(mode); 512 } 513 } 514 if (this.profileInfo_ && this.profileInfo_.filePath) { 515 chrome.send('profileIconSelectionChanged', 516 [this.profileInfo_.filePath, iconURL]); 517 } 518 }, 519 520 /** 521 * Updates the contents of the "Manage Profile" section of the dialog, 522 * and shows that section. 523 * @private 524 */ 525 prepareForManageDialog_: function() { 526 chrome.send('refreshGaiaPicture'); 527 var profileInfo = BrowserOptions.getCurrentProfile(); 528 ManageProfileOverlay.setProfileInfo(profileInfo, 'manage'); 529 $('manage-profile-overlay-create').hidden = true; 530 $('manage-profile-overlay-manage').hidden = false; 531 $('manage-profile-overlay-delete').hidden = true; 532 $('manage-profile-overlay-disconnect-managed').hidden = true; 533 $('manage-profile-name').disabled = profileInfo.isSupervised; 534 this.hideErrorBubble_('manage'); 535 }, 536 537 /** 538 * Display the "Manage Profile" dialog. 539 * @private 540 */ 541 showManageDialog_: function() { 542 this.prepareForManageDialog_(); 543 PageManager.showPageByName('manageProfile'); 544 }, 545 546 /** 547 * Display the "Delete Profile" dialog. 548 * @param {Object} profileInfo The profile object of the profile to delete. 549 * @private 550 */ 551 showDeleteDialog_: function(profileInfo) { 552 if (BrowserOptions.getCurrentProfile().isSupervised) 553 return; 554 555 ManageProfileOverlay.setProfileInfo(profileInfo, 'manage'); 556 $('manage-profile-overlay-create').hidden = true; 557 $('manage-profile-overlay-manage').hidden = true; 558 $('manage-profile-overlay-delete').hidden = false; 559 $('manage-profile-overlay-disconnect-managed').hidden = true; 560 $('delete-profile-icon').style.content = 561 getProfileAvatarIcon(profileInfo.iconURL); 562 $('delete-profile-text').textContent = 563 loadTimeData.getStringF('deleteProfileMessage', 564 elide(profileInfo.name, /* maxLength */ 50)); 565 $('delete-supervised-profile-addendum').hidden = 566 !profileInfo.isSupervised; 567 568 // Because this dialog isn't useful when refreshing or as part of the 569 // history, don't create a history entry for it when showing. 570 PageManager.showPageByName('manageProfile', false); 571 }, 572 573 /** 574 * Display the "Disconnect Managed Profile" dialog. 575 * @private 576 */ 577 showDisconnectManagedProfileDialog_: function(replacements) { 578 loadTimeData.overrideValues(replacements); 579 $('manage-profile-overlay-create').hidden = true; 580 $('manage-profile-overlay-manage').hidden = true; 581 $('manage-profile-overlay-delete').hidden = true; 582 $('disconnect-managed-profile-domain-information').innerHTML = 583 loadTimeData.getString('disconnectManagedProfileDomainInformation'); 584 $('disconnect-managed-profile-text').innerHTML = 585 loadTimeData.getString('disconnectManagedProfileText'); 586 $('manage-profile-overlay-disconnect-managed').hidden = false; 587 588 // Because this dialog isn't useful when refreshing or as part of the 589 // history, don't create a history entry for it when showing. 590 PageManager.showPageByName('manageProfile', false); 591 }, 592 593 /** 594 * Display the "Create Profile" dialog. 595 * @private 596 */ 597 showCreateDialog_: function() { 598 PageManager.showPageByName('createProfile'); 599 }, 600 }; 601 602 // Forward public APIs to private implementations. 603 cr.makePublic(ManageProfileOverlay, [ 604 'receiveDefaultProfileIconsAndNames', 605 'receiveNewProfileDefaults', 606 'receiveExistingProfileNames', 607 'receiveHasProfileShortcuts', 608 'setProfileInfo', 609 'setProfileName', 610 'showManageDialog', 611 'showDeleteDialog', 612 'showDisconnectManagedProfileDialog', 613 'showCreateDialog', 614 ]); 615 616 function CreateProfileOverlay() { 617 Page.call(this, 'createProfile', 618 loadTimeData.getString('createProfileTabTitle'), 619 'manage-profile-overlay'); 620 }; 621 622 cr.addSingletonGetter(CreateProfileOverlay); 623 624 CreateProfileOverlay.prototype = { 625 // Inherit from ManageProfileOverlay. 626 __proto__: ManageProfileOverlay.prototype, 627 628 // The signed-in email address of the current profile, or empty if they're 629 // not signed in. 630 signedInEmail_: '', 631 632 /** @override */ 633 canShowPage: function() { 634 return !BrowserOptions.getCurrentProfile().isSupervised; 635 }, 636 637 /** 638 * Configures the overlay to the "create user" mode. 639 * @override 640 */ 641 didShowPage: function() { 642 chrome.send('requestCreateProfileUpdate'); 643 chrome.send('requestDefaultProfileIcons', ['create']); 644 chrome.send('requestNewProfileDefaults'); 645 646 $('manage-profile-overlay-create').hidden = false; 647 $('manage-profile-overlay-manage').hidden = true; 648 $('manage-profile-overlay-delete').hidden = true; 649 $('manage-profile-overlay-disconnect-managed').hidden = true; 650 $('create-profile-instructions').textContent = 651 loadTimeData.getStringF('createProfileInstructions'); 652 this.hideErrorBubble_(); 653 this.updateCreateInProgress_(false); 654 655 var shortcutsEnabled = loadTimeData.getBoolean('profileShortcutsEnabled'); 656 $('create-shortcut-container').hidden = !shortcutsEnabled; 657 $('create-shortcut').checked = shortcutsEnabled; 658 659 $('create-profile-name-label').hidden = true; 660 $('create-profile-name').hidden = true; 661 $('create-profile-ok').disabled = true; 662 663 $('create-profile-supervised').checked = false; 664 $('import-existing-supervised-user-link').hidden = true; 665 $('create-profile-supervised').onchange = function() { 666 ManageProfileOverlay.getInstance().updateCreateOrImport_('create'); 667 }; 668 $('create-profile-supervised').hidden = true; 669 $('create-profile-supervised-signed-in').disabled = true; 670 $('create-profile-supervised-signed-in').hidden = true; 671 $('create-profile-supervised-not-signed-in').hidden = true; 672 673 this.profileNameIsDefault_ = false; 674 }, 675 676 /** @override */ 677 handleCancel: function() { 678 this.cancelCreateProfile_(); 679 }, 680 681 /** @override */ 682 showErrorBubble_: function(errorHtml) { 683 ManageProfileOverlay.getInstance().showErrorBubble_(errorHtml, 684 'create', 685 false); 686 }, 687 688 /** @override */ 689 hideErrorBubble_: function() { 690 ManageProfileOverlay.getInstance().hideErrorBubble_('create'); 691 }, 692 693 /** 694 * Updates the UI when a profile create step begins or ends. 695 * Note that hideErrorBubble_() also enables the "OK" button, so it 696 * must be called before this function if both are used. 697 * @param {boolean} inProgress True if the UI should be updated to show that 698 * profile creation is now in progress. 699 * @private 700 */ 701 updateCreateInProgress_: function(inProgress) { 702 this.createInProgress_ = inProgress; 703 this.updateCreateSupervisedUserCheckbox_(); 704 705 $('create-profile-icon-grid').disabled = inProgress; 706 $('create-profile-name').disabled = inProgress; 707 $('create-shortcut').disabled = inProgress; 708 $('create-profile-ok').disabled = inProgress; 709 $('import-existing-supervised-user-link').disabled = inProgress; 710 711 $('create-profile-throbber').hidden = !inProgress; 712 }, 713 714 /** 715 * Cancels the creation of the a profile. It is safe to call this even 716 * when no profile is in the process of being created. 717 * @private 718 */ 719 cancelCreateProfile_: function() { 720 PageManager.closeOverlay(); 721 chrome.send('cancelCreateProfile'); 722 this.hideErrorBubble_(); 723 this.updateCreateInProgress_(false); 724 }, 725 726 /** 727 * Shows an error message describing an error that occurred while creating 728 * a new profile. 729 * Called by BrowserOptions via the BrowserOptionsHandler. 730 * @param {string} error The error message to display. 731 * @private 732 */ 733 onError_: function(error) { 734 this.updateCreateInProgress_(false); 735 this.showErrorBubble_(error); 736 }, 737 738 /** 739 * Shows a warning message giving information while creating a new profile. 740 * Called by BrowserOptions via the BrowserOptionsHandler. 741 * @param {string} warning The warning message to display. 742 * @private 743 */ 744 onWarning_: function(warning) { 745 this.showErrorBubble_(warning); 746 }, 747 748 /** 749 * For new supervised users, shows a confirmation page after successfully 750 * creating a new profile; otherwise, the handler will open a new window. 751 * @param {Object} profileInfo An object of the form: 752 * profileInfo = { 753 * name: "Profile Name", 754 * filePath: "/path/to/profile/data/on/disk" 755 * isSupervised: (true|false), 756 * }; 757 * @private 758 */ 759 onSuccess_: function(profileInfo) { 760 this.updateCreateInProgress_(false); 761 PageManager.closeOverlay(); 762 if (profileInfo.isSupervised) { 763 options.SupervisedUserListData.resetPromise(); 764 profileInfo.custodianEmail = this.signedInEmail_; 765 SupervisedUserCreateConfirmOverlay.setProfileInfo(profileInfo); 766 PageManager.showPageByName('supervisedUserCreateConfirm', false); 767 BrowserOptions.updateManagesSupervisedUsers(true); 768 } 769 }, 770 771 /** 772 * Updates the signed-in or not-signed-in UI when in create mode. Called by 773 * the handler in response to the 'requestCreateProfileUpdate' message. 774 * updateSupervisedUsersAllowed_ is expected to be called after this is, and 775 * will update additional UI elements. 776 * @param {string} email The email address of the currently signed-in user. 777 * An empty string indicates that the user is not signed in. 778 * @param {boolean} hasError Whether the user's sign-in credentials are 779 * still valid. 780 * @private 781 */ 782 updateSignedInStatus_: function(email, hasError) { 783 this.signedInEmail_ = email; 784 this.hasError_ = hasError; 785 var isSignedIn = email !== ''; 786 $('create-profile-supervised').hidden = !isSignedIn; 787 $('create-profile-supervised-signed-in').hidden = !isSignedIn; 788 $('create-profile-supervised-not-signed-in').hidden = isSignedIn; 789 790 if (isSignedIn) { 791 var accountDetailsOutOfDate = 792 $('create-profile-supervised-account-details-out-of-date-label'); 793 accountDetailsOutOfDate.textContent = loadTimeData.getStringF( 794 'manageProfilesSupervisedAccountDetailsOutOfDate', email); 795 accountDetailsOutOfDate.hidden = !hasError; 796 797 $('create-profile-supervised-signed-in-label').textContent = 798 loadTimeData.getStringF( 799 'manageProfilesSupervisedSignedInLabel', email); 800 $('create-profile-supervised-signed-in-label').hidden = hasError; 801 802 $('create-profile-supervised-sign-in-again-link').hidden = !hasError; 803 $('create-profile-supervised-signed-in-learn-more-link').hidden = 804 hasError; 805 } 806 807 this.updateCreateSupervisedUserCheckbox_(); 808 // If we're signed in, showing/hiding import-existing-supervised-user-link 809 // is handled in receiveExistingSupervisedUsers_. 810 if (isSignedIn && !hasError) 811 this.requestExistingSupervisedUsers_(); 812 else 813 $('import-existing-supervised-user-link').hidden = true; 814 }, 815 816 /** 817 * Sets whether creating supervised users is allowed or not. Called by the 818 * handler in response to the 'requestCreateProfileUpdate' message or a 819 * change in the (policy-controlled) pref that prohibits creating supervised 820 * users, after the signed-in status has been updated. 821 * @param {boolean} allowed True if creating supervised users should be 822 * allowed. 823 * @private 824 */ 825 updateSupervisedUsersAllowed_: function(allowed) { 826 this.supervisedUsersAllowed_ = allowed; 827 this.updateCreateSupervisedUserCheckbox_(); 828 829 $('create-profile-supervised-sign-in-link').enabled = allowed; 830 if (!allowed) { 831 $('create-profile-supervised-indicator').setAttribute('controlled-by', 832 'policy'); 833 } else { 834 $('create-profile-supervised-indicator').removeAttribute( 835 'controlled-by'); 836 } 837 }, 838 839 /** 840 * Updates the status of the "create supervised user" checkbox. Called from 841 * updateSupervisedUsersAllowed_() or updateCreateInProgress_(). 842 * updateSignedInStatus_() does not call this method directly, because it 843 * will be followed by a call to updateSupervisedUsersAllowed_(). 844 * @private 845 */ 846 updateCreateSupervisedUserCheckbox_: function() { 847 $('create-profile-supervised').disabled = 848 !this.supervisedUsersAllowed_ || this.createInProgress_ || 849 this.signedInEmail_ == '' || this.hasError_; 850 }, 851 }; 852 853 // Forward public APIs to private implementations. 854 cr.makePublic(CreateProfileOverlay, [ 855 'cancelCreateProfile', 856 'onError', 857 'onSuccess', 858 'onWarning', 859 'updateCreateInProgress', 860 'updateSignedInStatus', 861 'updateSupervisedUsersAllowed', 862 ]); 863 864 // Export 865 return { 866 ManageProfileOverlay: ManageProfileOverlay, 867 CreateProfileOverlay: CreateProfileOverlay, 868 }; 869 }); 870