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 login.createScreen('GaiaSigninScreen', 'gaia-signin', function() {
10 // Gaia loading time after which error message must be displayed and
11 // lazy portal check should be fired.
12 /** @const */ var GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC = 7;
14 // GAIA animation guard timer. Started when GAIA page is loaded
15 // (Authenticator 'ready' event) and is intended to guard against edge cases
16 // when 'showView' message is not generated/received.
17 /** @const */ var GAIA_ANIMATION_GUARD_MILLISEC = 300;
19 // Maximum Gaia loading time in seconds.
20 /** @const */ var MAX_GAIA_LOADING_TIME_SEC = 60;
22 /** @const */ var HELP_TOPIC_ENTERPRISE_REPORTING = 2535613;
24 // The help topic regarding user not being in the whitelist.
25 /** @const */ var HELP_CANT_ACCESS_ACCOUNT = 188036;
27 // Amount of time the user has to be idle for before showing the online login
29 /** @const */ var IDLE_TIME_UNTIL_EXIT_OFFLINE_IN_MILLISECONDS = 180 * 1000;
31 // Approximate amount of time between checks to see if we should go to the
32 // online login page when we're in the offline login page and the device is
34 /** @const */ var IDLE_TIME_CHECK_FREQUENCY = 5 * 1000;
39 'updateAuthExtension',
44 'updateCancelButtonState',
45 'showWhitelistCheckFailedError',
49 * Frame loading error code (0 - no error).
56 * Saved gaia auth host load params.
60 gaiaAuthParams_: null,
63 * Whether local version of Gaia page is used.
70 * Whether new Gaia flow is active.
76 * Email of the user, which is logging in using offline mode.
82 * Whether consumer management enrollment is in progress.
86 isEnrollingConsumerManagement_: false,
89 * Timer id of pending load.
93 loadingTimer_: undefined,
96 * Timer id of a guard timer that is fired in case 'showView' message
97 * is not received from GAIA.
101 loadAnimationGuardTimer_: undefined,
104 * Whether we've processed 'showView' message - either from GAIA or from
109 showViewProcessed_: undefined,
112 * Whether user can cancel Gaia screen.
116 cancelAllowed_: undefined,
119 * Whether we should show user pods on the login screen.
123 isShowUsers_: undefined,
126 * SAML password confirmation attempt count.
129 samlPasswordConfirmAttempt_: 0,
132 * Do we currently have a setTimeout task running that tries to bring us
133 * back to the online login page after the user has idled for awhile? If so,
134 * then this id will be non-negative.
136 tryToGoToOnlineLoginPageCallbackId_: -1,
139 * The most recent period of time that the user has interacted. This is
140 * only updated when the offline page is active and the device is online.
142 mostRecentUserActivity_: Date.now(),
145 * Whether we should show webview based signin.
149 isWebviewSignin: false,
152 decorate: function() {
153 this.isWebviewSignin = loadTimeData.getValue('isWebviewSignin');
154 if (this.isWebviewSignin) {
155 // Replace iframe with webview.
156 var webview = this.ownerDocument.createElement('webview');
157 webview.id = 'signin-frame';
158 webview.name = 'signin-frame';
159 webview.hidden = true;
160 $('signin-frame').parentNode.replaceChild(webview, $('signin-frame'));
161 this.gaiaAuthHost_ = new cr.login.GaiaAuthHost(webview);
163 $('offline-gaia').addEventListener('authCompleted',
164 this.onAuthCompletedMessage_.bind(this));
166 this.gaiaAuthHost_ = new cr.login.GaiaAuthHost($('signin-frame'));
168 this.gaiaAuthHost_.addEventListener(
169 'ready', this.onAuthReady_.bind(this));
170 this.gaiaAuthHost_.addEventListener(
171 'dialogShown', this.onDialogShown_.bind(this));
172 this.gaiaAuthHost_.addEventListener(
173 'dialogHidden', this.onDialogHidden_.bind(this));
174 this.gaiaAuthHost_.addEventListener(
175 'backButton', this.onBackButton_.bind(this));
176 this.gaiaAuthHost_.addEventListener(
177 'showView', this.onShowView_.bind(this));
178 this.gaiaAuthHost_.confirmPasswordCallback =
179 this.onAuthConfirmPassword_.bind(this);
180 this.gaiaAuthHost_.noPasswordCallback =
181 this.onAuthNoPassword_.bind(this);
182 this.gaiaAuthHost_.insecureContentBlockedCallback =
183 this.onInsecureContentBlocked_.bind(this);
184 this.gaiaAuthHost_.missingGaiaInfoCallback =
185 this.missingGaiaInfo_.bind(this);
186 this.gaiaAuthHost_.samlApiUsedCallback =
187 this.samlApiUsed_.bind(this);
188 this.gaiaAuthHost_.addEventListener('authDomainChange',
189 this.onAuthDomainChange_.bind(this));
190 this.gaiaAuthHost_.addEventListener('authFlowChange',
191 this.onAuthFlowChange_.bind(this));
192 this.gaiaAuthHost_.addEventListener('authCompleted',
193 this.onAuthCompletedMessage_.bind(this));
194 this.gaiaAuthHost_.addEventListener('loadAbort',
195 this.onLoadAbortMessage_.bind(this));
196 this.gaiaAuthHost_.addEventListener(
197 'identifierEntered', this.onIdentifierEnteredMessage_.bind(this));
199 $('enterprise-info-hint-link').addEventListener('click', function(e) {
200 chrome.send('launchHelpApp', [HELP_TOPIC_ENTERPRISE_REPORTING]);
204 $('back-button-item').addEventListener('click', function(e) {
205 $('back-button-item').hidden = true;
206 $('signin-frame').back();
210 $('close-button-item').addEventListener('click', function(e) {
215 $('gaia-whitelist-error').addEventListener('buttonclick', function() {
216 this.showWhitelistCheckFailedError(false);
219 $('gaia-whitelist-error').addEventListener('linkclick', function() {
220 chrome.send('launchHelpApp', [HELP_CANT_ACCESS_ACCOUNT]);
223 this.updateLocalizedContent();
227 * Header text of the screen.
231 return loadTimeData.getString('signinScreenTitle');
235 * Returns true if local version of Gaia is used.
239 return this.isLocal_;
243 * Sets whether local version of Gaia is used.
244 * @param {boolean} value Whether local version of Gaia is used.
247 this.isLocal_ = value;
248 if (this.isNewGaiaFlow) {
249 $('signin-frame').hidden = this.isLocal_;
250 $('offline-gaia').hidden = !this.isLocal_;
252 chrome.send('updateOfflineLogin', [value]);
256 * This enables or disables trying to go back to the online login page
257 * after the user is idle for a few minutes, assuming that we're currently
258 * in the offline one. This is only applicable when the offline page is
259 * currently active. It is intended that when the device goes online, this
260 * gets called with true; when it goes offline, this gets called with
263 monitorOfflineIdle: function(shouldMonitor) {
264 var ACTIVITY_EVENTS = ['click', 'mousemove', 'keypress'];
267 // updateActivityTime_ is used as a callback for addEventListener, so we
268 // need the exact reference for removeEventListener. Because the callback
269 // needs to access the |this| as scoped inside of this function, we create
270 // a closure that uses the appropriate |this|.
272 // Unfourtantely, we cannot define this function inside of the JSON object
273 // as then we have to no way to create to capture the correct |this|
274 // reference. We define it here instead.
275 if (!self.updateActivityTime_) {
276 self.updateActivityTime_ = function() {
277 self.mostRecentUserActivity_ = Date.now();
283 // If we're not using the offline login page or we're already
284 // monitoring, then we don't need to do anything.
285 if (self.isLocal === false ||
286 self.tryToGoToOnlineLoginPageCallbackId_ !== -1)
289 self.mostRecentUserActivity_ = Date.now();
290 ACTIVITY_EVENTS.forEach(function(event) {
291 document.addEventListener(event, self.updateActivityTime_);
294 self.tryToGoToOnlineLoginPageCallbackId_ = setInterval(function() {
295 // If we're not in the offline page or the signin page, then we want
296 // to terminate monitoring.
297 if (self.isLocal === false ||
298 Oobe.getInstance().currentScreen.id != 'gaia-signin') {
299 self.monitorOfflineIdle(false);
303 var idleDuration = Date.now() - self.mostRecentUserActivity_;
304 if (idleDuration > IDLE_TIME_UNTIL_EXIT_OFFLINE_IN_MILLISECONDS) {
305 self.isLocal = false;
306 self.monitorOfflineIdle(false);
308 }, IDLE_TIME_CHECK_FREQUENCY);
313 // We're not monitoring, so we don't need to do anything.
314 if (self.tryToGoToOnlineLoginPageCallbackId_ === -1)
317 ACTIVITY_EVENTS.forEach(function(event) {
318 document.removeEventListener(event, self.updateActivityTime_);
320 clearInterval(self.tryToGoToOnlineLoginPageCallbackId_);
321 self.tryToGoToOnlineLoginPageCallbackId_ = -1;
326 * Shows/hides loading UI.
327 * @param {boolean} show True to show loading UI.
330 showLoadingUI_: function(show) {
331 $('gaia-loading').hidden = !show;
332 if (this.isNewGaiaFlow && this.isLocal) {
333 $('offline-gaia').hidden = show;
335 $('signin-frame').hidden = show;
337 $('signin-right').hidden = show;
338 $('enterprise-info-container').hidden = show;
339 $('gaia-signin-divider').hidden = show;
340 this.classList.toggle('loading', show);
341 $('signin-frame').classList.remove('show');
343 this.classList.remove('auth-completed');
347 * Handler for Gaia loading suspiciously long timeout.
350 onLoadingSuspiciouslyLong_: function() {
351 if (this != Oobe.getInstance().currentScreen)
353 chrome.send('showLoadingTimeoutError');
354 this.loadingTimer_ = setTimeout(
355 this.onLoadingTimeOut_.bind(this),
356 (MAX_GAIA_LOADING_TIME_SEC - GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC) *
361 * Handler for Gaia loading timeout.
364 onLoadingTimeOut_: function() {
365 this.loadingTimer_ = undefined;
366 chrome.send('showLoadingTimeoutError');
370 * Clears loading timer.
373 clearLoadingTimer_: function() {
374 if (this.loadingTimer_) {
375 clearTimeout(this.loadingTimer_);
376 this.loadingTimer_ = undefined;
381 * Sets up loading timer.
384 startLoadingTimer_: function() {
385 this.clearLoadingTimer_();
386 this.loadingTimer_ = setTimeout(
387 this.onLoadingSuspiciouslyLong_.bind(this),
388 GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC * 1000);
392 * Handler for GAIA animation guard timer.
395 onLoadAnimationGuardTimer_: function() {
396 this.loadAnimationGuardTimer_ = undefined;
401 * Clears GAIA animation guard timer.
404 clearLoadAnimationGuardTimer_: function() {
405 if (this.loadAnimationGuardTimer_) {
406 clearTimeout(this.loadAnimationGuardTimer_);
407 this.loadAnimationGuardTimer_ = undefined;
412 * Sets up GAIA animation guard timer.
415 startLoadAnimationGuardTimer_: function() {
416 this.clearLoadAnimationGuardTimer_();
417 this.loadAnimationGuardTimer_ = setTimeout(
418 this.onLoadAnimationGuardTimer_.bind(this),
419 GAIA_ANIMATION_GUARD_MILLISEC);
423 * Whether Gaia is loading.
427 return !$('gaia-loading').hidden;
429 set loading(loading) {
430 if (loading == this.loading)
433 this.showLoadingUI_(loading);
437 * Event handler that is invoked just before the frame is shown.
438 * @param {string} data Screen init payload. Url of auth extension start
441 onBeforeShow: function(data) {
442 chrome.send('loginUIStateChanged', ['gaia-signin', true]);
443 $('login-header-bar').signinUIState =
444 this.isEnrollingConsumerManagement_ ?
445 SIGNIN_UI_STATE.CONSUMER_MANAGEMENT_ENROLLMENT :
446 SIGNIN_UI_STATE.GAIA_SIGNIN;
448 // Ensure that GAIA signin (or loading UI) is actually visible.
449 window.requestAnimationFrame(function() {
450 chrome.send('loginVisible', ['gaia-loading']);
452 $('back-button-item').disabled = false;
453 $('back-button-item').hidden = true;
454 $('close-button-item').disabled = false;
455 this.classList.toggle('loading', this.loading);
457 // Button header is always visible when sign in is presented.
458 // Header is hidden once GAIA reports on successful sign in.
459 Oobe.getInstance().headerHidden = false;
462 onAfterShow: function(data) {
463 if (!this.loading && this.isWebviewSignin) {
465 $('offline-gaia').focus();
467 $('signin-frame').focus();
472 * Event handler that is invoked just before the screen is hidden.
474 onBeforeHide: function() {
475 chrome.send('loginUIStateChanged', ['gaia-signin', false]);
476 $('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN;
480 * Loads the authentication extension into the iframe.
481 * @param {Object} data Extension parameters bag.
484 loadAuthExtension: function(data) {
485 this.isNewGaiaFlow = data.useNewGaiaFlow;
486 this.isLocal = data.isLocal;
490 this.classList.toggle('full-width', false);
491 this.samlPasswordConfirmAttempt_ = 0;
493 this.updateAuthExtension(data);
496 for (var i in cr.login.GaiaAuthHost.SUPPORTED_PARAMS) {
497 var name = cr.login.GaiaAuthHost.SUPPORTED_PARAMS[i];
499 params[name] = data[name];
502 if (data.localizedStrings)
503 params.localizedStrings = data.localizedStrings;
505 if (this.isNewGaiaFlow) {
506 $('inner-container').classList.add('new-gaia-flow');
507 params.chromeType = data.chromeType;
508 params.isNewGaiaFlowChromeOS = true;
511 if (data.gaiaEndpoint)
512 params.gaiaPath = data.gaiaEndpoint;
514 $('login-header-bar').newGaiaFlow = this.isNewGaiaFlow;
516 // Screen size could have been changed because of 'new-gaia-flow' or
517 // 'full-width' classes.
518 if (Oobe.getInstance().currentScreen === this)
519 Oobe.getInstance().updateScreenSize(this);
521 if (data.forceReload ||
522 JSON.stringify(this.gaiaAuthParams_) != JSON.stringify(params)) {
525 var authMode = cr.login.GaiaAuthHost.AuthMode.DEFAULT;
527 authMode = cr.login.GaiaAuthHost.AuthMode.OFFLINE;
529 this.gaiaAuthParams_ = params;
531 this.startLoadingTimer_();
533 if (this.isLocal && this.isNewGaiaFlow) {
534 this.loadOffline(params);
537 this.gaiaAuthHost_.load(authMode,
539 this.onAuthCompleted_.bind(this));
541 } else if (this.loading && this.error_) {
542 // An error has occurred, so trying to reload.
548 * Updates the authentication extension with new parameters, if needed.
549 * @param {Object} data New extension parameters bag.
552 updateAuthExtension: function(data) {
553 if (this.isNewGaiaFlow) {
554 $('login-header-bar').showCreateSupervisedButton =
555 data.supervisedUsersEnabled && data.supervisedUsersCanCreate;
556 $('login-header-bar').showGuestButton = data.guestSignin;
558 $('createAccount').hidden = !data.createAccount;
559 $('guestSignin').hidden = !data.guestSignin;
560 $('createSupervisedUserPane').hidden = !data.supervisedUsersEnabled;
562 $('createSupervisedUserLinkPlaceholder').hidden =
563 !data.supervisedUsersCanCreate;
564 $('createSupervisedUserNoManagerText').hidden =
565 data.supervisedUsersCanCreate;
566 $('createSupervisedUserNoManagerText').textContent =
567 data.supervisedUsersRestrictionReason;
570 var isEnrollingConsumerManagement = data.isEnrollingConsumerManagement;
571 $('consumerManagementEnrollment').hidden = !isEnrollingConsumerManagement;
573 this.isShowUsers_ = data.isShowUsers;
574 this.updateCancelButtonState();
576 this.isEnrollingConsumerManagement_ = isEnrollingConsumerManagement;
578 // Sign-in right panel is hidden if all of its items are hidden.
579 var noRightPanel = $('createAccount').hidden &&
580 $('guestSignin').hidden &&
581 $('createSupervisedUserPane').hidden &&
582 $('consumerManagementEnrollment').hidden;
583 this.classList.toggle('no-right-panel', noRightPanel);
584 this.classList.toggle('full-width', false);
585 if (Oobe.getInstance().currentScreen === this)
586 Oobe.getInstance().updateScreenSize(this);
590 * Updates [Cancel] button state. Allow cancellation of screen only when
591 * user pods can be displayed.
593 updateCancelButtonState: function() {
594 this.cancelAllowed_ = this.isLocal ||
595 (this.isShowUsers_ && $('pod-row').pods.length);
596 $('login-header-bar').allowCancel = this.cancelAllowed_;
597 if (this.isNewGaiaFlow)
598 $('close-button-item').hidden = !this.cancelAllowed_;
602 * Whether the current auth flow is SAML.
605 return this.gaiaAuthHost_.authFlow ==
606 cr.login.GaiaAuthHost.AuthFlow.SAML;
610 * Invoked when the authDomain property is changed on the GAIA host.
612 onAuthDomainChange_: function() {
613 $('saml-notice-message').textContent = loadTimeData.getStringF(
615 this.gaiaAuthHost_.authDomain);
619 * Invoked when the authFlow property is changed on the GAIA host.
620 * @param {Event} e Property change event.
622 onAuthFlowChange_: function(e) {
623 var isSAML = this.isSAML();
625 this.classList.toggle('no-right-panel', isSAML);
626 this.classList.toggle('full-width', isSAML);
627 $('saml-notice-container').hidden = !isSAML;
629 if (Oobe.getInstance().currentScreen === this) {
630 Oobe.getInstance().updateScreenSize(this);
631 $('login-header-bar').allowCancel = isSAML || this.cancelAllowed_;
632 if (this.isNewGaiaFlow)
633 $('close-button-item').hidden = !(isSAML || this.cancelAllowed_);
638 * Invoked when the auth host emits 'ready' event.
641 onAuthReady_: function() {
642 showViewProcessed_ = false;
643 if (this.isNewGaiaFlow)
644 this.startLoadAnimationGuardTimer_();
646 this.clearLoadingTimer_();
647 this.loading = false;
649 if (!this.isNewGaiaFlow)
650 this.onLoginUIVisible_();
652 // Warm up the user images screen.
653 Oobe.getInstance().preloadScreen({id: SCREEN_USER_IMAGE_PICKER});
657 * Invoked when the auth host emits 'dialogShown' event.
660 onDialogShown_: function() {
661 $('back-button-item').disabled = true;
662 $('close-button-item').disabled = true;
666 * Invoked when the auth host emits 'dialogHidden' event.
669 onDialogHidden_: function() {
670 $('back-button-item').disabled = false;
671 $('close-button-item').disabled = false;
675 * Invoked when the auth host emits 'backButton' event.
678 onBackButton_: function(e) {
679 $('back-button-item').hidden = !e.detail;
680 $('login-header-bar').updateUI_();
681 $('signin-frame').focus();
685 * Invoked when the auth host emits 'showView' event or when corresponding
689 onShowView_: function(e) {
690 if (showViewProcessed_)
693 showViewProcessed_ = true;
694 this.clearLoadAnimationGuardTimer_();
695 $('signin-frame').classList.add('show');
696 this.onLoginUIVisible_();
700 * Called when UI is shown.
703 onLoginUIVisible_: function() {
704 // Show deferred error bubble.
705 if (this.errorBubble_) {
706 this.showErrorBubble(this.errorBubble_[0], this.errorBubble_[1]);
707 this.errorBubble_ = undefined;
710 chrome.send('loginWebuiReady');
711 chrome.send('loginVisible', ['gaia-signin']);
715 * Invoked when the user has successfully authenticated via SAML, the
716 * principals API was not used and the auth host needs the user to confirm
717 * the scraped password.
718 * @param {string} email The authenticated user's e-mail.
719 * @param {number} passwordCount The number of passwords that were scraped.
722 onAuthConfirmPassword_: function(email, passwordCount) {
724 Oobe.getInstance().headerHidden = false;
726 if (this.samlPasswordConfirmAttempt_ == 0)
727 chrome.send('scrapedPasswordCount', [passwordCount]);
729 if (this.samlPasswordConfirmAttempt_ < 2) {
730 login.ConfirmPasswordScreen.show(
732 this.samlPasswordConfirmAttempt_,
733 this.onConfirmPasswordCollected_.bind(this));
735 chrome.send('scrapedPasswordVerificationFailed');
736 this.showFatalAuthError(
737 loadTimeData.getString('fatalErrorMessageVerificationFailed'),
738 loadTimeData.getString('fatalErrorTryAgainButton'));
740 if (this.isNewGaiaFlow) {
741 this.classList.toggle('no-right-panel', false);
742 this.classList.toggle('full-width', false);
747 * Invoked when the confirm password screen is dismissed.
750 onConfirmPasswordCollected_: function(password) {
751 this.samlPasswordConfirmAttempt_++;
752 this.gaiaAuthHost_.verifyConfirmedPassword(password);
754 // Shows signin UI again without changing states.
755 Oobe.showScreen({id: SCREEN_GAIA_SIGNIN});
759 * Inovked when the user has successfully authenticated via SAML, the
760 * principals API was not used and no passwords could be scraped.
761 * @param {string} email The authenticated user's e-mail.
763 onAuthNoPassword_: function(email) {
764 this.showFatalAuthError(
765 loadTimeData.getString('fatalErrorMessageNoPassword'),
766 loadTimeData.getString('fatalErrorTryAgainButton'));
767 chrome.send('scrapedPasswordCount', [0]);
771 * Invoked when the authentication flow had to be aborted because content
772 * served over an unencrypted connection was detected. Shows a fatal error.
773 * This method is only called on Chrome OS, where the entire authentication
774 * flow is required to be encrypted.
775 * @param {string} url The URL that was blocked.
777 onInsecureContentBlocked_: function(url) {
778 this.showFatalAuthError(
779 loadTimeData.getStringF('fatalErrorMessageInsecureURL', url),
780 loadTimeData.getString('fatalErrorDoneButton'));
784 * Shows the fatal auth error.
785 * @param {string} message The error message to show.
786 * @param {string} buttonLabel The label to display on dismiss button.
788 showFatalAuthError: function(message, buttonLabel) {
789 login.FatalErrorScreen.show(message, buttonLabel, Oobe.showSigninUI);
793 * Show fatal auth error when information is missing from GAIA.
795 missingGaiaInfo_: function() {
796 this.showFatalAuthError(
797 loadTimeData.getString('fatalErrorMessageNoAccountDetails'),
798 loadTimeData.getString('fatalErrorTryAgainButton'));
802 * Record that SAML API was used during sign-in.
804 samlApiUsed_: function() {
805 chrome.send('usingSAMLAPI');
809 * Invoked when auth is completed successfully.
810 * @param {!Object} credentials Credentials of the completed authentication.
813 onAuthCompleted_: function(credentials) {
814 if (credentials.useOffline) {
815 this.email = credentials.email;
816 chrome.send('authenticateUser',
818 credentials.password]);
819 } else if (credentials.authCode) {
820 if (credentials.hasOwnProperty('authCodeOnly') &&
821 credentials.authCodeOnly) {
822 chrome.send('completeAuthenticationAuthCodeOnly',
823 [credentials.authCode]);
825 chrome.send('completeAuthentication', [
828 credentials.password,
829 credentials.authCode,
830 credentials.usingSAML,
831 credentials.gapsCookie
835 chrome.send('completeLogin',
838 credentials.password,
839 credentials.usingSAML]);
843 this.classList.add('auth-completed');
844 // Now that we're in logged in state header should be hidden.
845 Oobe.getInstance().headerHidden = true;
846 // Clear any error messages that were shown before login.
851 * Invoked when onAuthCompleted message received.
852 * @param {!Object} e Payload of the received HTML5 message.
855 onAuthCompletedMessage_: function(e) {
856 this.onAuthCompleted_(e.detail);
860 * Invoked when onLoadAbort message received.
861 * @param {!Object} e Payload of the received HTML5 message.
864 onLoadAbortMessage_: function(e) {
865 this.onWebviewError(e.detail);
869 * Invoked when identifierEntered message received.
870 * @param {!Object} e Payload of the received HTML5 message.
873 onIdentifierEnteredMessage_: function(e) {
874 this.onIdentifierEntered(e.detail);
878 * Clears input fields and switches to input mode.
879 * @param {boolean} takeFocus True to take focus.
880 * @param {boolean} forceOnline Whether online sign-in should be forced.
881 * If |forceOnline| is false previously used sign-in type will be used.
883 reset: function(takeFocus, forceOnline) {
884 // Reload and show the sign-in UI if needed.
886 if (!forceOnline && this.isLocal) {
887 // Show 'Cancel' button to allow user to return to the main screen
888 // (e.g. this makes sense when connection is back).
889 Oobe.getInstance().headerHidden = false;
890 $('login-header-bar').signinUIState = SIGNIN_UI_STATE.GAIA_SIGNIN;
891 // Do nothing, since offline version is reloaded after an error comes.
899 * Reloads extension frame.
901 doReload: function() {
905 this.gaiaAuthHost_.reload();
907 this.startLoadingTimer_();
911 * Updates localized content of the screen that is not updated via template.
913 updateLocalizedContent: function() {
914 $('createAccount').innerHTML = loadTimeData.getStringF(
916 '<a id="createAccountLink" class="signin-link" href="#">',
918 $('guestSignin').innerHTML = loadTimeData.getStringF(
920 '<a id="guestSigninLink" class="signin-link" href="#">',
922 $('createSupervisedUserLinkPlaceholder').innerHTML =
923 loadTimeData.getStringF(
924 'createSupervisedUser',
925 '<a id="createSupervisedUserLink" class="signin-link" href="#">',
927 $('consumerManagementEnrollment').innerHTML = loadTimeData.getString(
928 'consumerManagementEnrollmentSigninMessage');
929 $('createAccountLink').addEventListener('click', function(e) {
930 chrome.send('createAccount');
933 $('guestSigninLink').addEventListener('click', function(e) {
934 chrome.send('launchIncognito');
937 $('createSupervisedUserLink').addEventListener('click', function(e) {
938 chrome.send('showSupervisedUserCreationScreen');
944 * Shows sign-in error bubble.
945 * @param {number} loginAttempts Number of login attemps tried.
946 * @param {HTMLElement} content Content to show in bubble.
948 showErrorBubble: function(loginAttempts, error) {
950 $('add-user-button').hidden = true;
951 $('cancel-add-user-button').hidden = false;
952 // Reload offline version of the sign-in extension, which will show
954 chrome.send('offlineLogin', [this.email]);
955 } else if (!this.loading) {
956 // We want to show bubble near "Email" field, but we can't calculate
957 // it's position because it is located inside iframe. So we only
958 // can hardcode some constants.
959 /** @const */ var ERROR_BUBBLE_OFFSET = 84;
960 /** @const */ var ERROR_BUBBLE_PADDING = 0;
961 $('bubble').showContentForElement($('login-box'),
962 cr.ui.Bubble.Attachment.LEFT,
965 ERROR_BUBBLE_PADDING);
967 // Defer the bubble until the frame has been loaded.
968 this.errorBubble_ = [loginAttempts, error];
973 * Called when user canceled signin.
976 if (!this.cancelAllowed_) {
977 // In OOBE signin screen, cancel is not allowed because there is
978 // no other screen to show. If user is in middle of a saml flow,
979 // reset signin screen to get out of the saml flow.
981 Oobe.resetSigninUI(true);
986 $('offline-gaia').switchToEmailCard();
988 this.classList.remove('whitelist-error');
993 * Handler for iframe's error notification coming from the outside.
994 * For more info see C++ class 'WebUILoginView' which calls this method.
995 * @param {number} error Error code.
996 * @param {string} url The URL that failed to load.
998 onFrameError: function(error, url) {
1000 chrome.send('frameLoadingCompleted', [this.error_]);
1004 * Handler for webview error handling.
1005 * @param {!Object} data Additional information about error event like:
1006 * {string} error Error code such as "ERR_INTERNET_DISCONNECTED".
1007 * {string} url The URL that failed to load.
1009 onWebviewError: function(data) {
1010 chrome.send('webviewLoadAborted', [data.error]);
1014 * Handler for identifierEntered event.
1015 * @param {!Object} data The identifier entered by user:
1016 * {string} accountIdentifier User identifier.
1018 onIdentifierEntered: function(data) {
1019 chrome.send('identifierEntered', [data.accountIdentifier]);
1023 * Sets welcome and enterpriseinfo strings for offline gaia.
1024 * Also sets callback and sends message whether we already have email and
1025 * should switch to the password screen with error.
1027 loadOffline: function(params) {
1028 var offlineLogin = $('offline-gaia');
1029 var strings = params.localizedStrings;
1030 if ('stringEnterpriseInfo' in strings)
1031 offlineLogin.enterpriseInfo = strings['stringEnterpriseInfo'];
1032 if ('emailDomain' in params)
1033 offlineLogin.emailDomain = '@' + params['emailDomain'];
1034 offlineLogin.setEmail(params.email);
1038 * Show/Hide error when user is not in whitelist. When UI is hidden
1040 * @param {boolean} show Show/hide error UI.
1041 * @param {!Object} opt_data Optional additional information.
1043 showWhitelistCheckFailedError: function(show, opt_data) {
1045 var isManaged = opt_data && opt_data.enterpriseManaged;
1046 $('gaia-whitelist-error').textContent =
1047 loadTimeData.getValue(isManaged ? 'whitelistErrorEnterprise' :
1048 'whitelistErrorConsumer');
1051 this.classList.toggle('whitelist-error', show);
1052 this.loading = !show;
1055 Oobe.showSigninUI();