- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / chromeos / login / display_manager.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 /**
6  * @fileoverview Display manager for WebUI OOBE and login.
7  */
8
9 // TODO(xiyuan): Find a better to share those constants.
10 /** @const */ var SCREEN_OOBE_NETWORK = 'connect';
11 /** @const */ var SCREEN_OOBE_EULA = 'eula';
12 /** @const */ var SCREEN_OOBE_UPDATE = 'update';
13 /** @const */ var SCREEN_OOBE_ENROLLMENT = 'oauth-enrollment';
14 /** @const */ var SCREEN_OOBE_KIOSK_ENABLE = 'kiosk-enable';
15 /** @const */ var SCREEN_GAIA_SIGNIN = 'gaia-signin';
16 /** @const */ var SCREEN_ACCOUNT_PICKER = 'account-picker';
17 /** @const */ var SCREEN_ERROR_MESSAGE = 'error-message';
18 /** @const */ var SCREEN_USER_IMAGE_PICKER = 'user-image';
19 /** @const */ var SCREEN_TPM_ERROR = 'tpm-error-message';
20 /** @const */ var SCREEN_PASSWORD_CHANGED = 'password-changed';
21 /** @const */ var SCREEN_CREATE_MANAGED_USER_FLOW =
22     'managed-user-creation';
23 /** @const */ var SCREEN_APP_LAUNCH_SPLASH = 'app-launch-splash';
24 /** @const */ var SCREEN_CONFIRM_PASSWORD = 'confirm-password';
25 /** @const */ var SCREEN_MESSAGE_BOX = 'message-box';
26
27 /* Accelerator identifiers. Must be kept in sync with webui_login_view.cc. */
28 /** @const */ var ACCELERATOR_CANCEL = 'cancel';
29 /** @const */ var ACCELERATOR_ENROLLMENT = 'enrollment';
30 /** @const */ var ACCELERATOR_KIOSK_ENABLE = 'kiosk_enable';
31 /** @const */ var ACCELERATOR_VERSION = 'version';
32 /** @const */ var ACCELERATOR_RESET = 'reset';
33 /** @const */ var ACCELERATOR_LEFT = 'left';
34 /** @const */ var ACCELERATOR_RIGHT = 'right';
35 /** @const */ var ACCELERATOR_DEVICE_REQUISITION = 'device_requisition';
36 /** @const */ var ACCELERATOR_DEVICE_REQUISITION_REMORA =
37     'device_requisition_remora';
38 /** @const */ var ACCELERATOR_APP_LAUNCH_BAILOUT = 'app_launch_bailout';
39
40 /* Help topic identifiers. */
41 /** @const */ var HELP_TOPIC_ENTERPRISE_REPORTING = 2535613;
42
43 /* Signin UI state constants. Used to control header bar UI. */
44 /** @const */ var SIGNIN_UI_STATE = {
45   HIDDEN: 0,
46   GAIA_SIGNIN: 1,
47   ACCOUNT_PICKER: 2,
48   WRONG_HWID_WARNING: 3,
49   MANAGED_USER_CREATION_FLOW: 4,
50 };
51
52 /* Possible UI states of the error screen. */
53 /** @const */ var ERROR_SCREEN_UI_STATE = {
54   UNKNOWN: 'ui-state-unknown',
55   UPDATE: 'ui-state-update',
56   SIGNIN: 'ui-state-signin',
57   MANAGED_USER_CREATION_FLOW: 'ui-state-locally-managed',
58   KIOSK_MODE: 'ui-state-kiosk-mode',
59   LOCAL_STATE_ERROR: 'ui-state-local-state-error'
60 };
61
62 /* Possible types of UI. */
63 /** @const */ var DISPLAY_TYPE = {
64   UNKNOWN: 'unknown',
65   OOBE: 'oobe',
66   LOGIN: 'login',
67   LOCK: 'lock',
68   USER_ADDING: 'user-adding',
69   APP_LAUNCH_SPLASH: 'app-launch-splash'
70 };
71
72 cr.define('cr.ui.login', function() {
73   var Bubble = cr.ui.Bubble;
74
75   /**
76    * Maximum time in milliseconds to wait for step transition to finish.
77    * The value is used as the duration for ensureTransitionEndEvent below.
78    * It needs to be inline with the step screen transition duration time
79    * defined in css file. The current value in css is 200ms. To avoid emulated
80    * webkitTransitionEnd fired before real one, 250ms is used.
81    * @const
82    */
83   var MAX_SCREEN_TRANSITION_DURATION = 250;
84
85   /**
86    * Groups of screens (screen IDs) that should have the same dimensions.
87    * @type Array.<Array.<string>>
88    * @const
89    */
90   var SCREEN_GROUPS = [[SCREEN_OOBE_NETWORK,
91                         SCREEN_OOBE_EULA,
92                         SCREEN_OOBE_UPDATE]
93                       ];
94
95   /**
96    * Constructor a display manager that manages initialization of screens,
97    * transitions, error messages display.
98    *
99    * @constructor
100    */
101   function DisplayManager() {
102   }
103
104   DisplayManager.prototype = {
105     /**
106      * Registered screens.
107      */
108     screens_: [],
109
110     /**
111      * Current OOBE step, index in the screens array.
112      * @type {number}
113      */
114     currentStep_: 0,
115
116     /**
117      * Whether version label can be toggled by ACCELERATOR_VERSION.
118      * @type {boolean}
119      */
120     allowToggleVersion_: false,
121
122     /**
123      * Whether keyboard navigation flow is enforced.
124      * @type {boolean}
125      */
126     forceKeyboardFlow_: false,
127
128     /**
129      * Type of UI.
130      * @type {string}
131      */
132     displayType_: DISPLAY_TYPE.UNKNOWN,
133
134     get displayType() {
135       return this.displayType_;
136     },
137
138     set displayType(displayType) {
139       this.displayType_ = displayType;
140     },
141
142     /**
143      * Gets current screen element.
144      * @type {HTMLElement}
145      */
146     get currentScreen() {
147       return $(this.screens_[this.currentStep_]);
148     },
149
150     /**
151      * Hides/shows header (Shutdown/Add User/Cancel buttons).
152      * @param {boolean} hidden Whether header is hidden.
153      */
154     set headerHidden(hidden) {
155       $('login-header-bar').hidden = hidden;
156     },
157
158     /**
159      * Toggles background of main body between transparency and solid.
160      * @param {boolean} solid Whether to show a solid background.
161      */
162     set solidBackground(solid) {
163       if (solid)
164         document.body.classList.add('solid');
165       else
166         document.body.classList.remove('solid');
167     },
168
169     /**
170      * Forces keyboard based OOBE navigation.
171      * @param {boolean} value True if keyboard navigation flow is forced.
172      */
173     set forceKeyboardFlow(value) {
174       this.forceKeyboardFlow_ = value;
175       if (value)
176         keyboard.initializeKeyboardFlow();
177     },
178
179     /**
180      * Shows/hides version labels.
181      * @param {boolean} show Whether labels should be visible by default. If
182      *     false, visibility can be toggled by ACCELERATOR_VERSION.
183      */
184     showVersion: function(show) {
185       $('version-labels').hidden = !show;
186       this.allowToggleVersion_ = !show;
187     },
188
189     /**
190      * Handle accelerators.
191      * @param {string} name Accelerator name.
192      */
193     handleAccelerator: function(name) {
194       if (name == ACCELERATOR_CANCEL) {
195         if (this.currentScreen.cancel) {
196           this.currentScreen.cancel();
197         }
198       } else if (name == ACCELERATOR_ENROLLMENT) {
199         var currentStepId = this.screens_[this.currentStep_];
200         if (currentStepId == SCREEN_GAIA_SIGNIN ||
201             currentStepId == SCREEN_ACCOUNT_PICKER) {
202           chrome.send('toggleEnrollmentScreen');
203         } else if (currentStepId == SCREEN_OOBE_NETWORK ||
204                    currentStepId == SCREEN_OOBE_EULA) {
205           // In this case update check will be skipped and OOBE will
206           // proceed straight to enrollment screen when EULA is accepted.
207           chrome.send('skipUpdateEnrollAfterEula');
208         } else if (currentStepId == SCREEN_OOBE_ENROLLMENT) {
209           // This accelerator is also used to manually cancel auto-enrollment.
210           if (this.currentScreen.cancelAutoEnrollment)
211             this.currentScreen.cancelAutoEnrollment();
212         }
213       } else if (name == ACCELERATOR_KIOSK_ENABLE) {
214         var currentStepId = this.screens_[this.currentStep_];
215         if (currentStepId == SCREEN_GAIA_SIGNIN ||
216             currentStepId == SCREEN_ACCOUNT_PICKER) {
217           chrome.send('toggleKioskEnableScreen');
218         }
219       } else if (name == ACCELERATOR_VERSION) {
220         if (this.allowToggleVersion_)
221           $('version-labels').hidden = !$('version-labels').hidden;
222       } else if (name == ACCELERATOR_RESET) {
223         var currentStepId = this.screens_[this.currentStep_];
224         if (currentStepId == SCREEN_GAIA_SIGNIN ||
225             currentStepId == SCREEN_ACCOUNT_PICKER) {
226           chrome.send('toggleResetScreen');
227         }
228       } else if (name == ACCELERATOR_DEVICE_REQUISITION) {
229         if (this.isOobeUI())
230           this.showDeviceRequisitionPrompt_();
231       } else if (name == ACCELERATOR_DEVICE_REQUISITION_REMORA) {
232         if (this.isOobeUI()) {
233           this.deviceRequisition_ = 'remora';
234           this.showDeviceRequisitionPrompt_();
235         }
236       } else if (name == ACCELERATOR_APP_LAUNCH_BAILOUT) {
237         var currentStepId = this.screens_[this.currentStep_];
238         if (currentStepId == SCREEN_APP_LAUNCH_SPLASH)
239           chrome.send('cancelAppLaunch');
240       }
241
242       if (!this.forceKeyboardFlow_)
243         return;
244
245       // Handle special accelerators for keyboard enhanced navigation flow.
246       if (name == ACCELERATOR_LEFT)
247         keyboard.raiseKeyFocusPrevious(document.activeElement);
248       else if (name == ACCELERATOR_RIGHT)
249         keyboard.raiseKeyFocusNext(document.activeElement);
250     },
251
252     /**
253      * Appends buttons to the button strip.
254      * @param {Array.<HTMLElement>} buttons Array with the buttons to append.
255      * @param {string} screenId Id of the screen that buttons belong to.
256      */
257     appendButtons_: function(buttons, screenId) {
258       if (buttons) {
259         var buttonStrip = $(screenId + '-controls');
260         if (buttonStrip) {
261           for (var i = 0; i < buttons.length; ++i)
262             buttonStrip.appendChild(buttons[i]);
263         }
264       }
265     },
266
267     /**
268      * Disables or enables control buttons on the specified screen.
269      * @param {HTMLElement} screen Screen which controls should be affected.
270      * @param {boolean} disabled Whether to disable controls.
271      */
272     disableButtons_: function(screen, disabled) {
273       var buttons = document.querySelectorAll(
274           '#' + screen.id + '-controls button:not(.preserve-disabled-state)');
275       for (var i = 0; i < buttons.length; ++i) {
276         buttons[i].disabled = disabled;
277       }
278     },
279
280     /**
281      * Updates a step's css classes to reflect left, current, or right position.
282      * @param {number} stepIndex step index.
283      * @param {string} state one of 'left', 'current', 'right'.
284      */
285     updateStep_: function(stepIndex, state) {
286       var stepId = this.screens_[stepIndex];
287       var step = $(stepId);
288       var header = $('header-' + stepId);
289       var states = ['left', 'right', 'current'];
290       for (var i = 0; i < states.length; ++i) {
291         if (states[i] != state) {
292           step.classList.remove(states[i]);
293           header.classList.remove(states[i]);
294         }
295       }
296       step.classList.add(state);
297       header.classList.add(state);
298     },
299
300     /**
301      * Switches to the next OOBE step.
302      * @param {number} nextStepIndex Index of the next step.
303      */
304     toggleStep_: function(nextStepIndex, screenData) {
305       var currentStepId = this.screens_[this.currentStep_];
306       var nextStepId = this.screens_[nextStepIndex];
307       var oldStep = $(currentStepId);
308       var newStep = $(nextStepId);
309       var newHeader = $('header-' + nextStepId);
310
311       // Disable controls before starting animation.
312       this.disableButtons_(oldStep, true);
313
314       if (oldStep.onBeforeHide)
315         oldStep.onBeforeHide();
316
317       if (newStep.onBeforeShow)
318         newStep.onBeforeShow(screenData);
319
320       newStep.classList.remove('hidden');
321
322       if (newStep.onAfterShow)
323         newStep.onAfterShow(screenData);
324
325       this.disableButtons_(newStep, false);
326
327       // Default control to be focused (if specified).
328       var defaultControl = newStep.defaultControl;
329
330       if (this.isOobeUI()) {
331         // Start gliding animation for OOBE steps.
332         if (nextStepIndex > this.currentStep_) {
333           for (var i = this.currentStep_; i < nextStepIndex; ++i)
334             this.updateStep_(i, 'left');
335           this.updateStep_(nextStepIndex, 'current');
336         } else if (nextStepIndex < this.currentStep_) {
337           for (var i = this.currentStep_; i > nextStepIndex; --i)
338             this.updateStep_(i, 'right');
339           this.updateStep_(nextStepIndex, 'current');
340         }
341       } else {
342         // Start fading animation for login display.
343         oldStep.classList.add('faded');
344         newStep.classList.remove('faded');
345       }
346
347       // Adjust inner container height based on new step's height.
348       this.updateScreenSize(newStep);
349
350       var innerContainer = $('inner-container');
351       if (this.currentStep_ != nextStepIndex &&
352           !oldStep.classList.contains('hidden')) {
353         if (oldStep.classList.contains('animated')) {
354           innerContainer.classList.add('animation');
355           oldStep.addEventListener('webkitTransitionEnd', function f(e) {
356             oldStep.removeEventListener('webkitTransitionEnd', f);
357             if (oldStep.classList.contains('faded') ||
358                 oldStep.classList.contains('left') ||
359                 oldStep.classList.contains('right')) {
360               innerContainer.classList.remove('animation');
361               oldStep.classList.add('hidden');
362             }
363             // Refresh defaultControl. It could have changed.
364             var defaultControl = newStep.defaultControl;
365             if (defaultControl)
366               defaultControl.focus();
367           });
368           ensureTransitionEndEvent(oldStep, MAX_SCREEN_TRANSITION_DURATION);
369         } else {
370           oldStep.classList.add('hidden');
371           if (defaultControl)
372             defaultControl.focus();
373         }
374       } else {
375         // First screen on OOBE launch.
376         if (this.isOobeUI() && innerContainer.classList.contains('down')) {
377           innerContainer.classList.remove('down');
378           innerContainer.addEventListener(
379               'webkitTransitionEnd', function f(e) {
380                 innerContainer.removeEventListener('webkitTransitionEnd', f);
381                 $('progress-dots').classList.remove('down');
382                 chrome.send('loginVisible', ['oobe']);
383                 // Refresh defaultControl. It could have changed.
384                 var defaultControl = newStep.defaultControl;
385                 if (defaultControl)
386                   defaultControl.focus();
387               });
388           ensureTransitionEndEvent(innerContainer,
389                                    MAX_SCREEN_TRANSITION_DURATION);
390         } else {
391           if (defaultControl)
392             defaultControl.focus();
393           chrome.send('loginVisible', ['oobe']);
394         }
395       }
396       this.currentStep_ = nextStepIndex;
397       $('oobe').className = nextStepId;
398
399       $('step-logo').hidden = newStep.classList.contains('no-logo');
400
401       chrome.send('updateCurrentScreen', [this.currentScreen.id]);
402     },
403
404     /**
405      * Make sure that screen is initialized and decorated.
406      * @param {Object} screen Screen params dict, e.g. {id: screenId, data: {}}.
407      */
408     preloadScreen: function(screen) {
409       var screenEl = $(screen.id);
410       if (screenEl.deferredDecorate !== undefined) {
411         screenEl.deferredDecorate();
412         delete screenEl.deferredDecorate;
413       }
414     },
415
416     /**
417      * Show screen of given screen id.
418      * @param {Object} screen Screen params dict, e.g. {id: screenId, data: {}}.
419      */
420     showScreen: function(screen) {
421       var screenId = screen.id;
422
423       // Make sure the screen is decorated.
424       this.preloadScreen(screen);
425
426       if (screen.data !== undefined && screen.data.disableAddUser)
427         DisplayManager.updateAddUserButtonStatus(true);
428
429
430       // Show sign-in screen instead of account picker if pod row is empty.
431       if (screenId == SCREEN_ACCOUNT_PICKER && $('pod-row').pods.length == 0) {
432         // Manually hide 'add-user' header bar, because of the case when
433         // 'Cancel' button is used on the offline login page.
434         $('add-user-header-bar-item').hidden = true;
435         Oobe.showSigninUI(true);
436         return;
437       }
438
439       var data = screen.data;
440       var index = this.getScreenIndex_(screenId);
441       if (index >= 0)
442         this.toggleStep_(index, data);
443     },
444
445     /**
446      * Gets index of given screen id in screens_.
447      * @param {string} screenId Id of the screen to look up.
448      * @private
449      */
450     getScreenIndex_: function(screenId) {
451       for (var i = 0; i < this.screens_.length; ++i) {
452         if (this.screens_[i] == screenId)
453           return i;
454       }
455       return -1;
456     },
457
458     /**
459      * Register an oobe screen.
460      * @param {Element} el Decorated screen element.
461      */
462     registerScreen: function(el) {
463       var screenId = el.id;
464       this.screens_.push(screenId);
465
466       var header = document.createElement('span');
467       header.id = 'header-' + screenId;
468       header.textContent = el.header ? el.header : '';
469       header.className = 'header-section';
470       $('header-sections').appendChild(header);
471
472       var dot = document.createElement('div');
473       dot.id = screenId + '-dot';
474       dot.className = 'progdot';
475       var progressDots = $('progress-dots');
476       if (progressDots)
477         progressDots.appendChild(dot);
478
479       this.appendButtons_(el.buttons, screenId);
480     },
481
482     /**
483      * Updates inner container size based on the size of the current screen and
484      * other screens in the same group.
485      * Should be executed on screen change / screen size change.
486      * @param {!HTMLElement} screen Screen that is being shown.
487      */
488     updateScreenSize: function(screen) {
489       // Have to reset any previously predefined screen size first
490       // so that screen contents would define it instead (offsetHeight/width).
491       // http://crbug.com/146539
492       $('inner-container').style.height = '';
493       $('inner-container').style.width = '';
494       screen.style.width = '';
495       screen.style.height = '';
496
497      $('outer-container').classList.toggle(
498         'fullscreen', screen.classList.contains('fullscreen'));
499
500       var height = screen.offsetHeight;
501       var width = screen.offsetWidth;
502       for (var i = 0, screenGroup; screenGroup = SCREEN_GROUPS[i]; i++) {
503         if (screenGroup.indexOf(screen.id) != -1) {
504           // Set screen dimensions to maximum dimensions within this group.
505           for (var j = 0, screen2; screen2 = $(screenGroup[j]); j++) {
506             height = Math.max(height, screen2.offsetHeight);
507             width = Math.max(width, screen2.offsetWidth);
508           }
509           break;
510         }
511       }
512       $('inner-container').style.height = height + 'px';
513       $('inner-container').style.width = width + 'px';
514       // This requires |screen| to have 'box-sizing: border-box'.
515       screen.style.width = width + 'px';
516       screen.style.height = height + 'px';
517     },
518
519     /**
520      * Updates localized content of the screens like headers, buttons and links.
521      * Should be executed on language change.
522      */
523     updateLocalizedContent_: function() {
524       for (var i = 0, screenId; screenId = this.screens_[i]; ++i) {
525         var screen = $(screenId);
526         var buttonStrip = $(screenId + '-controls');
527         if (buttonStrip)
528           buttonStrip.innerHTML = '';
529         // TODO(nkostylev): Update screen headers for new OOBE design.
530         this.appendButtons_(screen.buttons, screenId);
531         if (screen.updateLocalizedContent)
532           screen.updateLocalizedContent();
533       }
534
535       var currentScreenId = this.screens_[this.currentStep_];
536       var currentScreen = $(currentScreenId);
537       this.updateScreenSize(currentScreen);
538
539       // Trigger network drop-down to reload its state
540       // so that strings are reloaded.
541       // Will be reloaded if drowdown is actually shown.
542       cr.ui.DropDown.refresh();
543     },
544
545     /**
546      * Prepares screens to use in login display.
547      */
548     prepareForLoginDisplay_: function() {
549       for (var i = 0, screenId; screenId = this.screens_[i]; ++i) {
550         var screen = $(screenId);
551         screen.classList.add('faded');
552         screen.classList.remove('right');
553         screen.classList.remove('left');
554       }
555     },
556
557     /**
558      * Shows the device requisition prompt.
559      */
560     showDeviceRequisitionPrompt_: function() {
561       if (!this.deviceRequisitionDialog_) {
562         this.deviceRequisitionDialog_ =
563             new cr.ui.dialogs.PromptDialog(document.body);
564         this.deviceRequisitionDialog_.setOkLabel(
565             loadTimeData.getString('deviceRequisitionPromptOk'));
566         this.deviceRequisitionDialog_.setCancelLabel(
567             loadTimeData.getString('deviceRequisitionPromptCancel'));
568       }
569       this.deviceRequisitionDialog_.show(
570           loadTimeData.getString('deviceRequisitionPromptText'),
571           this.deviceRequisition_,
572           this.onConfirmDeviceRequisitionPrompt_.bind(this));
573     },
574
575     /**
576      * Confirmation handle for the device requisition prompt.
577      * @param {string} value The value entered by the user.
578      */
579     onConfirmDeviceRequisitionPrompt_: function(value) {
580       this.deviceRequisition_ = value;
581       chrome.send('setDeviceRequisition', [value]);
582     },
583
584     /*
585      * Updates the device requisition string shown in the requisition prompt.
586      * @param {string} requisition The device requisition.
587      */
588     updateDeviceRequisition: function(requisition) {
589       this.deviceRequisition_ = requisition;
590     },
591
592     /**
593      * Returns true if Oobe UI is shown.
594      */
595     isOobeUI: function() {
596       return document.body.classList.contains('oobe-display');
597     },
598
599     /**
600      * Returns true if sign in UI should trigger wallpaper load on boot.
601      */
602     shouldLoadWallpaperOnBoot: function() {
603       return loadTimeData.getString('bootIntoWallpaper') == 'on';
604     },
605   };
606
607   /**
608    * Initializes display manager.
609    */
610   DisplayManager.initialize = function() {
611     // Extracting display type from URL.
612     var path = window.location.pathname.substr(1);
613     var displayType = DISPLAY_TYPE.UNKNOWN;
614     Object.getOwnPropertyNames(DISPLAY_TYPE).forEach(function(type) {
615       if (DISPLAY_TYPE[type] == path) {
616         displayType = path;
617       }
618     });
619     if (displayType == DISPLAY_TYPE.UNKNOWN) {
620       console.error("Unknown display type '" + path + "'. Setting default.");
621       displayType = DISPLAY_TYPE.LOGIN;
622     }
623     Oobe.getInstance().displayType = displayType;
624     document.documentElement.setAttribute('screen', displayType);
625
626     var link = $('enterprise-info-hint-link');
627     link.addEventListener(
628         'click', DisplayManager.handleEnterpriseHintLinkClick);
629   },
630
631   /**
632    * Returns offset (top, left) of the element.
633    * @param {!Element} element HTML element.
634    * @return {!Object} The offset (top, left).
635    */
636   DisplayManager.getOffset = function(element) {
637     var x = 0;
638     var y = 0;
639     while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) {
640       x += element.offsetLeft - element.scrollLeft;
641       y += element.offsetTop - element.scrollTop;
642       element = element.offsetParent;
643     }
644     return { top: y, left: x };
645   };
646
647   /**
648    * Returns position (top, left, right, bottom) of the element.
649    * @param {!Element} element HTML element.
650    * @return {!Object} Element position (top, left, right, bottom).
651    */
652   DisplayManager.getPosition = function(element) {
653     var offset = DisplayManager.getOffset(element);
654     return { top: offset.top,
655              right: window.innerWidth - element.offsetWidth - offset.left,
656              bottom: window.innerHeight - element.offsetHeight - offset.top,
657              left: offset.left };
658   };
659
660   /**
661    * Disables signin UI.
662    */
663   DisplayManager.disableSigninUI = function() {
664     $('login-header-bar').disabled = true;
665     $('pod-row').disabled = true;
666   };
667
668   /**
669    * Shows signin UI.
670    * @param {string} opt_email An optional email for signin UI.
671    */
672   DisplayManager.showSigninUI = function(opt_email) {
673     var currentScreenId = Oobe.getInstance().currentScreen.id;
674     if (currentScreenId == SCREEN_GAIA_SIGNIN)
675       $('login-header-bar').signinUIState = SIGNIN_UI_STATE.GAIA_SIGNIN;
676     else if (currentScreenId == SCREEN_ACCOUNT_PICKER)
677       $('login-header-bar').signinUIState = SIGNIN_UI_STATE.ACCOUNT_PICKER;
678     chrome.send('showAddUser', [opt_email]);
679   };
680
681   /**
682    * Resets sign-in input fields.
683    * @param {boolean} forceOnline Whether online sign-in should be forced.
684    *     If |forceOnline| is false previously used sign-in type will be used.
685    */
686   DisplayManager.resetSigninUI = function(forceOnline) {
687     var currentScreenId = Oobe.getInstance().currentScreen.id;
688
689     $(SCREEN_GAIA_SIGNIN).reset(
690         currentScreenId == SCREEN_GAIA_SIGNIN, forceOnline);
691     $('login-header-bar').disabled = false;
692     $('pod-row').reset(currentScreenId == SCREEN_ACCOUNT_PICKER);
693   };
694
695   /**
696    * Shows sign-in error bubble.
697    * @param {number} loginAttempts Number of login attemps tried.
698    * @param {string} message Error message to show.
699    * @param {string} link Text to use for help link.
700    * @param {number} helpId Help topic Id associated with help link.
701    */
702   DisplayManager.showSignInError = function(loginAttempts, message, link,
703                                             helpId) {
704     var error = document.createElement('div');
705
706     var messageDiv = document.createElement('div');
707     messageDiv.className = 'error-message-bubble';
708     messageDiv.textContent = message;
709     error.appendChild(messageDiv);
710
711     if (link) {
712       messageDiv.classList.add('error-message-bubble-padding');
713
714       var helpLink = document.createElement('a');
715       helpLink.href = '#';
716       helpLink.textContent = link;
717       helpLink.addEventListener('click', function(e) {
718         chrome.send('launchHelpApp', [helpId]);
719         e.preventDefault();
720       });
721       error.appendChild(helpLink);
722     }
723
724     var currentScreen = Oobe.getInstance().currentScreen;
725     if (currentScreen && typeof currentScreen.showErrorBubble === 'function')
726       currentScreen.showErrorBubble(loginAttempts, error);
727   };
728
729   /**
730    * Shows password changed screen that offers migration.
731    * @param {boolean} showError Whether to show the incorrect password error.
732    */
733   DisplayManager.showPasswordChangedScreen = function(showError) {
734     login.PasswordChangedScreen.show(showError);
735   };
736
737   /**
738    * Shows dialog to create managed user.
739    */
740   DisplayManager.showManagedUserCreationScreen = function() {
741     login.ManagedUserCreationScreen.show();
742   };
743
744   /**
745    * Shows TPM error screen.
746    */
747   DisplayManager.showTpmError = function() {
748     login.TPMErrorMessageScreen.show();
749   };
750
751   /**
752    * Clears error bubble.
753    */
754   DisplayManager.clearErrors = function() {
755     $('bubble').hide();
756   };
757
758   /**
759    * Sets text content for a div with |labelId|.
760    * @param {string} labelId Id of the label div.
761    * @param {string} labelText Text for the label.
762    */
763   DisplayManager.setLabelText = function(labelId, labelText) {
764     $(labelId).textContent = labelText;
765   };
766
767   /**
768    * Shows help topic about enrolled devices.
769    * @param {MouseEvent} Event object.
770    */
771   DisplayManager.handleEnterpriseHintLinkClick = function(e) {
772     chrome.send('launchHelpApp', [HELP_TOPIC_ENTERPRISE_REPORTING]);
773     e.preventDefault();
774   }
775
776   /**
777    * Sets the text content of the enterprise info message.
778    * @param {string} messageText The message text.
779    */
780   DisplayManager.setEnterpriseInfo = function(messageText) {
781     $('enterprise-info-message').textContent = messageText;
782     if (messageText) {
783       $('enterprise-info').hidden = false;
784     }
785   };
786
787   /**
788    * Disable Add users button if said.
789    * @param {boolean} disable true to disable
790    */
791   DisplayManager.updateAddUserButtonStatus = function(disable) {
792     $('add-user-button').disabled = disable;
793     $('add-user-button').classList[
794         disable ? 'add' : 'remove']('button-restricted');
795     $('add-user-button').title = disable ?
796         loadTimeData.getString('disabledAddUserTooltip') : '';
797   }
798
799   /**
800    * Clears password field in user-pod.
801    */
802   DisplayManager.clearUserPodPassword = function() {
803     $('pod-row').clearFocusedPod();
804   };
805
806   /**
807    * Restores input focus to currently selected pod.
808    */
809   DisplayManager.refocusCurrentPod = function() {
810     $('pod-row').refocusCurrentPod();
811   };
812
813   // Export
814   return {
815     DisplayManager: DisplayManager
816   };
817 });