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