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