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