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