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.
6 * @fileoverview Oobe signin screen implementation.
9 <include src="../../gaia_auth_host/gaia_auth_host.js"></include>
11 login.createScreen('GaiaSigninScreen', 'gaia-signin', function() {
12 // Gaia loading time after which error message must be displayed and
13 // lazy portal check should be fired.
14 /** @const */ var GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC = 7;
16 // Maximum Gaia loading time in seconds.
17 /** @const */ var MAX_GAIA_LOADING_TIME_SEC = 60;
19 /** @const */ var HELP_TOPIC_ENTERPRISE_REPORTING = 2535613;
24 'updateAuthExtension',
30 * Frame loading error code (0 - no error).
37 * Saved gaia auth host load params.
41 gaiaAuthParams_: null,
44 * Whether local version of Gaia page is used.
51 * Email of the user, which is logging in using offline mode.
57 * Timer id of pending load.
61 loadingTimer_: undefined,
64 * Whether user can cancel Gaia screen.
68 cancelAllowed_: undefined,
71 decorate: function() {
72 this.gaiaAuthHost_ = new cr.login.GaiaAuthHost($('signin-frame'));
73 this.gaiaAuthHost_.addEventListener(
74 'ready', this.onAuthReady_.bind(this));
75 this.gaiaAuthHost_.confirmPasswordCallback =
76 this.onAuthConfirmPassword_.bind(this);
77 this.gaiaAuthHost_.noPasswordCallback =
78 this.onAuthNoPassword_.bind(this);
79 this.gaiaAuthHost_.authPageLoadedCallback =
80 this.onAuthPageLoaded_.bind(this);
82 $('enterprise-info-hint-link').addEventListener('click', function(e) {
83 chrome.send('launchHelpApp', [HELP_TOPIC_ENTERPRISE_REPORTING]);
88 this.updateLocalizedContent();
92 * Header text of the screen.
96 return loadTimeData.getString('signinScreenTitle');
100 * Returns true if local version of Gaia is used.
104 return this.isLocal_;
108 * Sets whether local version of Gaia is used.
109 * @param {boolean} value Whether local version of Gaia is used.
112 this.isLocal_ = value;
113 chrome.send('updateOfflineLogin', [value]);
117 * Shows/hides loading UI.
118 * @param {boolean} show True to show loading UI.
121 showLoadingUI_: function(show) {
122 $('gaia-loading').hidden = !show;
123 this.gaiaAuthHost_.frame.hidden = show;
124 $('signin-right').hidden = show;
125 $('enterprise-info-container').hidden = show;
126 $('gaia-signin-divider').hidden = show;
130 * Handler for Gaia loading suspiciously long timeout.
133 onLoadingSuspiciouslyLong_: function() {
134 if (this != Oobe.getInstance().currentScreen)
136 chrome.send('showLoadingTimeoutError');
137 this.loadingTimer_ = window.setTimeout(
138 this.onLoadingTimeOut_.bind(this),
139 (MAX_GAIA_LOADING_TIME_SEC - GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC) *
144 * Handler for Gaia loading timeout.
147 onLoadingTimeOut_: function() {
148 this.loadingTimer_ = undefined;
149 chrome.send('showLoadingTimeoutError');
153 * Clears loading timer.
156 clearLoadingTimer_: function() {
157 if (this.loadingTimer_) {
158 window.clearTimeout(this.loadingTimer_);
159 this.loadingTimer_ = undefined;
164 * Sets up loading timer.
167 startLoadingTimer_: function() {
168 this.clearLoadingTimer_();
169 this.loadingTimer_ = window.setTimeout(
170 this.onLoadingSuspiciouslyLong_.bind(this),
171 GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC * 1000);
175 * Whether Gaia is loading.
179 return !$('gaia-loading').hidden;
181 set loading(loading) {
182 if (loading == this.loading)
185 this.showLoadingUI_(loading);
189 * Event handler that is invoked just before the frame is shown.
190 * @param {string} data Screen init payload. Url of auth extension start
193 onBeforeShow: function(data) {
194 chrome.send('loginUIStateChanged', ['gaia-signin', true]);
195 $('login-header-bar').signinUIState = SIGNIN_UI_STATE.GAIA_SIGNIN;
197 // Ensure that GAIA signin (or loading UI) is actually visible.
198 window.webkitRequestAnimationFrame(function() {
199 chrome.send('loginVisible', ['gaia-loading']);
202 // Announce the name of the screen, if accessibility is on.
203 $('gaia-signin-aria-label').setAttribute(
204 'aria-label', loadTimeData.getString('signinScreenTitle'));
206 // Button header is always visible when sign in is presented.
207 // Header is hidden once GAIA reports on successful sign in.
208 Oobe.getInstance().headerHidden = false;
212 * Event handler that is invoked just before the screen is hidden.
214 onBeforeHide: function() {
215 chrome.send('loginUIStateChanged', ['gaia-signin', false]);
216 $('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN;
220 * Loads the authentication extension into the iframe.
221 * @param {Object} data Extension parameters bag.
224 loadAuthExtension: function(data) {
225 this.isLocal = data.isLocal;
227 this.classList.toggle('saml', false);
229 this.updateAuthExtension(data);
232 for (var i in cr.login.GaiaAuthHost.SUPPORTED_PARAMS) {
233 var name = cr.login.GaiaAuthHost.SUPPORTED_PARAMS[i];
235 params[name] = data[name];
238 if (data.localizedStrings)
239 params.localizedStrings = data.localizedStrings;
241 if (data.forceReload ||
242 JSON.stringify(this.gaiaAuthParams_) != JSON.stringify(params)) {
244 this.gaiaAuthHost_.load(data.useOffline ?
245 cr.login.GaiaAuthHost.AuthMode.OFFLINE :
246 cr.login.GaiaAuthHost.AuthMode.DEFAULT,
248 this.onAuthCompleted_.bind(this));
249 this.gaiaAuthParams_ = params;
252 this.startLoadingTimer_();
253 } else if (this.loading && this.error_) {
254 // An error has occurred, so trying to reload.
260 * Updates the authentication extension with new parameters, if needed.
261 * @param {Object} data New extension parameters bag.
264 updateAuthExtension: function(data) {
265 var reasonLabel = $('gaia-signin-reason');
266 if (data.passwordChanged) {
267 reasonLabel.textContent =
268 loadTimeData.getString('signinScreenPasswordChanged');
269 reasonLabel.hidden = false;
271 reasonLabel.hidden = true;
274 $('createAccount').hidden = !data.createAccount;
275 $('guestSignin').hidden = !data.guestSignin;
276 $('createManagedUserPane').hidden = !data.managedUsersEnabled;
278 $('createManagedUserLinkPlaceholder').hidden =
279 !data.managedUsersCanCreate;
280 $('createManagedUserNoManagerText').hidden = data.managedUsersCanCreate;
281 $('createManagedUserNoManagerText').textContent =
282 data.managedUsersRestrictionReason;
284 // Allow cancellation of screen only when user pods can be displayed.
285 this.cancelAllowed_ = data.isShowUsers && $('pod-row').pods.length;
286 $('login-header-bar').allowCancel = this.cancelAllowed_;
288 // Sign-in right panel is hidden if all of its items are hidden.
289 var noRightPanel = $('gaia-signin-reason').hidden &&
290 $('createAccount').hidden &&
291 $('guestSignin').hidden &&
292 $('createManagedUserPane').hidden;
293 this.classList.toggle('no-right-panel', noRightPanel);
294 if (Oobe.getInstance().currentScreen === this)
295 Oobe.getInstance().updateScreenSize(this);
299 * Invoked when the auth host notifies about an auth page is loaded.
300 * @param {boolean} isSAML True if the loaded auth page is SAML.
302 onAuthPageLoaded_: function(isSAML) {
303 this.classList.toggle('saml', isSAML);
304 if (Oobe.getInstance().currentScreen === this)
305 Oobe.getInstance().updateScreenSize(this);
309 * Invoked when the auth host emits 'ready' event.
312 onAuthReady_: function() {
313 this.loading = false;
314 this.clearLoadingTimer_();
316 // Show deferred error bubble.
317 if (this.errorBubble_) {
318 this.showErrorBubble(this.errorBubble_[0], this.errorBubble_[1]);
319 this.errorBubble_ = undefined;
322 chrome.send('loginWebuiReady');
323 chrome.send('loginVisible', ['gaia-signin']);
325 // Warm up the user images screen.
326 Oobe.getInstance().preloadScreen({id: SCREEN_USER_IMAGE_PICKER});
330 * Invoked when the auth host needs the user to confirm password.
333 onAuthConfirmPassword_: function() {
335 Oobe.getInstance().headerHidden = false;
337 login.ConfirmPasswordScreen.show(
338 this.onConfirmPasswordCollected_.bind(this));
342 * Invoked when the confirm password screen is dismissed.
345 onConfirmPasswordCollected_: function(password) {
346 this.gaiaAuthHost_.verifyConfirmedPassword(password);
348 // Shows signin UI again without changing states.
349 Oobe.showScreen({id: SCREEN_GAIA_SIGNIN});
353 * Inovked when the auth flow completes but no password is available.
354 * @param {string} email The authenticated user email.
356 onAuthNoPassword_: function(email) {
357 login.MessageBoxScreen.show(
358 loadTimeData.getString('noPasswordWarningTitle'),
359 loadTimeData.getString('noPasswordWarningBody'),
360 loadTimeData.getString('noPasswordWarningOkButton'),
365 * Invoked when auth is completed successfully.
366 * @param {!Object} credentials Credentials of the completed authentication.
369 onAuthCompleted_: function(credentials) {
370 if (credentials.useOffline) {
371 this.email = credentials.email;
372 chrome.send('authenticateUser',
373 [credentials.email, credentials.password]);
374 } else if (credentials.authCode) {
375 chrome.send('completeAuthentication',
377 credentials.password,
378 credentials.authCode]);
380 chrome.send('completeLogin',
381 [credentials.email, credentials.password]);
385 // Now that we're in logged in state header should be hidden.
386 Oobe.getInstance().headerHidden = true;
387 // Clear any error messages that were shown before login.
392 * Clears input fields and switches to input mode.
393 * @param {boolean} takeFocus True to take focus.
394 * @param {boolean} forceOnline Whether online sign-in should be forced.
395 * If |forceOnline| is false previously used sign-in type will be used.
397 reset: function(takeFocus, forceOnline) {
398 // Reload and show the sign-in UI if needed.
400 if (!forceOnline && this.isLocal) {
401 // Show 'Cancel' button to allow user to return to the main screen
402 // (e.g. this makes sense when connection is back).
403 Oobe.getInstance().headerHidden = false;
404 $('login-header-bar').signinUIState = SIGNIN_UI_STATE.GAIA_SIGNIN;
405 // Do nothing, since offline version is reloaded after an error comes.
413 * Reloads extension frame.
415 doReload: function() {
417 this.gaiaAuthHost_.reload();
419 this.startLoadingTimer_();
423 * Updates localized content of the screen that is not updated via template.
425 updateLocalizedContent: function() {
426 $('createAccount').innerHTML = loadTimeData.getStringF(
428 '<a id="createAccountLink" class="signin-link" href="#">',
430 $('guestSignin').innerHTML = loadTimeData.getStringF(
432 '<a id="guestSigninLink" class="signin-link" href="#">',
434 $('createManagedUserLinkPlaceholder').innerHTML = loadTimeData.getStringF(
435 'createLocallyManagedUser',
436 '<a id="createManagedUserLink" class="signin-link" href="#">',
438 $('createAccountLink').addEventListener('click', function(e) {
439 chrome.send('createAccount');
442 $('guestSigninLink').addEventListener('click', function(e) {
443 chrome.send('launchIncognito');
446 $('createManagedUserLink').addEventListener('click', function(e) {
447 chrome.send('showLocallyManagedUserCreationScreen');
453 * Shows sign-in error bubble.
454 * @param {number} loginAttempts Number of login attemps tried.
455 * @param {HTMLElement} content Content to show in bubble.
457 showErrorBubble: function(loginAttempts, error) {
459 $('add-user-button').hidden = true;
460 $('cancel-add-user-button').hidden = false;
461 // Reload offline version of the sign-in extension, which will show
463 chrome.send('offlineLogin', [this.email]);
464 } else if (!this.loading) {
465 // We want to show bubble near "Email" field, but we can't calculate
466 // it's position because it is located inside iframe. So we only
467 // can hardcode some constants.
468 /** @const */ var ERROR_BUBBLE_OFFSET = 84;
469 /** @const */ var ERROR_BUBBLE_PADDING = 0;
470 $('bubble').showContentForElement($('login-box'),
471 cr.ui.Bubble.Attachment.LEFT,
474 ERROR_BUBBLE_PADDING);
476 // Defer the bubble until the frame has been loaded.
477 this.errorBubble_ = [loginAttempts, error];
482 * Called when user canceled signin.
485 if (!this.cancelAllowed_)
487 $('pod-row').loadLastWallpaper();
488 Oobe.showScreen({id: SCREEN_ACCOUNT_PICKER});
489 Oobe.resetSigninUI(true);
493 * Handler for iframe's error notification coming from the outside.
494 * For more info see C++ class 'SnifferObserver' which calls this method.
495 * @param {number} error Error code.
497 onFrameError: function(error) {
499 chrome.send('frameLoadingCompleted', [this.error_]);