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