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