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