Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(307)

Side by Side Diff: ui/login/account_picker/md_user_pod_row.js

Issue 2910203003: Handling edge cases of new login screen (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview User pod row implementation. 6 * @fileoverview User pod row implementation.
7 */ 7 */
8 8
9 cr.define('login', function() { 9 cr.define('login', function() {
10 /** 10 /**
11 * Number of displayed columns depending on user pod count.
12 * @type {Array<number>}
13 * @const
14 */
15 var COLUMNS = [0, 1, 2, 3, 4, 5, 4, 4, 4, 5, 5, 6, 6, 5, 5, 6, 6, 6, 6];
16
17 /**
18 * Mapping between number of columns in pod-row and margin between user pods
19 * for such layout.
20 * @type {Array<number>}
21 * @const
22 */
23 var MARGIN_BY_COLUMNS = [undefined, 40, 40, 40, 40, 40, 12];
24
25 /**
26 * Mapping between number of columns in the desktop pod-row and margin
27 * between user pods for such layout.
28 * @type {Array<number>}
29 * @const
30 */
31 var DESKTOP_MARGIN_BY_COLUMNS = [undefined, 32, 32, 32, 32, 32, 32];
32
33 /**
34 * Maximal number of columns currently supported by pod-row.
35 * @type {number}
36 * @const
37 */
38 var MAX_NUMBER_OF_COLUMNS = 6;
39
40 /**
41 * Maximal number of rows if sign-in banner is displayed alonside.
42 * @type {number}
43 * @const
44 */
45 var MAX_NUMBER_OF_ROWS_UNDER_SIGNIN_BANNER = 2;
46
47 /**
48 * Variables used for pod placement processing. Width and height should be 11 * Variables used for pod placement processing. Width and height should be
49 * synced with computed CSS sizes of pods. 12 * synced with computed CSS sizes of pods.
50 */ 13 */
51 var CROS_POD_WIDTH = 306; 14 var CROS_POD_WIDTH = 306;
52 var CROS_SMALL_POD_WIDTH = 304; 15 var CROS_SMALL_POD_WIDTH = 304;
53 var CROS_EXTRA_SMALL_POD_WIDTH = 282; 16 var CROS_EXTRA_SMALL_POD_WIDTH = 282;
54 var DESKTOP_POD_WIDTH = 180; 17 var DESKTOP_POD_WIDTH = 180;
55 var MD_DESKTOP_POD_WIDTH = 160; 18 var MD_DESKTOP_POD_WIDTH = 160;
56 var PUBLIC_EXPANDED_BASIC_WIDTH = 500; 19 var PUBLIC_EXPANDED_BASIC_WIDTH = 500;
57 var PUBLIC_EXPANDED_ADVANCED_WIDTH = 610; 20 var PUBLIC_EXPANDED_ADVANCED_WIDTH = 610;
58 var CROS_POD_HEIGHT = 346; 21 var CROS_POD_HEIGHT = 346;
59 var CROS_SMALL_POD_HEIGHT = 74; 22 var CROS_SMALL_POD_HEIGHT = 74;
60 var CROS_EXTRA_SMALL_POD_HEIGHT = 60; 23 var CROS_EXTRA_SMALL_POD_HEIGHT = 60;
61 var DESKTOP_POD_HEIGHT = 226; 24 var DESKTOP_POD_HEIGHT = 226;
62 var MD_DESKTOP_POD_HEIGHT = 200; 25 var MD_DESKTOP_POD_HEIGHT = 200;
63 var POD_ROW_PADDING = 10; 26 var POD_ROW_PADDING = 10;
64 var DESKTOP_ROW_PADDING = 32; 27 var DESKTOP_ROW_PADDING = 32;
65 var CUSTOM_ICON_CONTAINER_SIZE = 40; 28 var CUSTOM_ICON_CONTAINER_SIZE = 40;
66 var CROS_PIN_POD_HEIGHT = 417; 29 var CROS_PIN_POD_HEIGHT = 417;
67 var SCROLL_MASK_HEIGHT = 112; 30 var SCROLL_MASK_HEIGHT = 112;
31 var BANNER_MESSAGE_WIDTH = 520;
68 32
69 /** 33 /**
70 * The maximum number of users that each pod placement method can handle. 34 * The maximum number of users that each pod placement method can handle.
71 */ 35 */
72 var POD_ROW_LIMIT = 2; 36 var POD_ROW_LIMIT = 2;
73 var LANDSCAPE_MODE_LIMIT = 6; 37 var LANDSCAPE_MODE_LIMIT = 6;
74 var PORTRAIT_MODE_LIMIT = 9; 38 var PORTRAIT_MODE_LIMIT = 9;
75 39
76 /** 40 /**
77 * Minimal padding between user pod and virtual keyboard. 41 * Minimal padding between user pod and virtual keyboard.
(...skipping 899 matching lines...) Expand 10 before | Expand all | Expand 10 after
977 */ 941 */
978 get nameElement() { 942 get nameElement() {
979 return this.querySelector('.name'); 943 return this.querySelector('.name');
980 }, 944 },
981 945
982 /** 946 /**
983 * Gets image element of the small pod. 947 * Gets image element of the small pod.
984 * @type {!HTMLImageElement} 948 * @type {!HTMLImageElement}
985 */ 949 */
986 get smallPodImageElement() { 950 get smallPodImageElement() {
987 return this.querySelector('.small-pod-image'); 951 return this.querySelector('.user-image.small-pod-image');
988 }, 952 },
989 953
990 /** 954 /**
991 * Gets name element of the small pod. 955 * Gets name element of the small pod.
992 * @type {!HTMLDivElement} 956 * @type {!HTMLDivElement}
993 */ 957 */
994 get smallPodNameElement() { 958 get smallPodNameElement() {
995 return this.querySelector('.small-pod-name'); 959 return this.querySelector('.small-pod-name');
996 }, 960 },
997 961
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
1409 } 1373 }
1410 1374
1411 // Hide user-type-bubble. 1375 // Hide user-type-bubble.
1412 this.userTypeBubbleElement.classList.remove('bubble-shown'); 1376 this.userTypeBubbleElement.classList.remove('bubble-shown');
1413 1377
1414 this.actionBoxAreaElement.classList.add('active'); 1378 this.actionBoxAreaElement.classList.add('active');
1415 1379
1416 // Invisible focus causes ChromeVox to read user name and email. 1380 // Invisible focus causes ChromeVox to read user name and email.
1417 this.actionBoxMenuTitleElement.tabIndex = UserPodTabOrder.POD_MENU_ITEM; 1381 this.actionBoxMenuTitleElement.tabIndex = UserPodTabOrder.POD_MENU_ITEM;
1418 this.actionBoxMenuTitleElement.focus(); 1382 this.actionBoxMenuTitleElement.focus();
1419
1420 // If the user pod is on either edge of the screen, then the menu
1421 // could be displayed partially ofscreen.
1422 this.actionBoxMenu.classList.remove('left-edge-offset');
1423 this.actionBoxMenu.classList.remove('right-edge-offset');
1424
1425 var offsetLeft =
1426 cr.ui.login.DisplayManager.getOffset(this.actionBoxMenu).left;
1427 var menuWidth = this.actionBoxMenu.offsetWidth;
1428 if (offsetLeft < 0)
1429 this.actionBoxMenu.classList.add('left-edge-offset');
1430 else if (offsetLeft + menuWidth > window.innerWidth)
1431 this.actionBoxMenu.classList.add('right-edge-offset');
1432 } else { 1383 } else {
1433 this.actionBoxAreaElement.classList.remove('active'); 1384 this.actionBoxAreaElement.classList.remove('active');
1434 this.actionBoxAreaElement.classList.remove('menu-moved-up'); 1385 this.actionBoxAreaElement.classList.remove('menu-moved-up');
1435 this.actionBoxMenu.classList.remove('menu-moved-up'); 1386 this.actionBoxMenu.classList.remove('menu-moved-up');
1436 } 1387 }
1437 }, 1388 },
1438 1389
1439 /** 1390 /**
1440 * Whether action box button is in hovered state. 1391 * Whether action box button is in hovered state.
1441 * @type {boolean} 1392 * @type {boolean}
(...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after
2128 * @param {Event} e Click event. 2079 * @param {Event} e Click event.
2129 */ 2080 */
2130 handleClickOnPod_: function(e) { 2081 handleClickOnPod_: function(e) {
2131 if (this.parentNode.disabled) 2082 if (this.parentNode.disabled)
2132 return; 2083 return;
2133 2084
2134 if (this.getPodStyle() != UserPod.Style.LARGE) { 2085 if (this.getPodStyle() != UserPod.Style.LARGE) {
2135 $('pod-row').switchMainPod(this); 2086 $('pod-row').switchMainPod(this);
2136 return; 2087 return;
2137 } 2088 }
2089 Oobe.clearErrors();
2138 2090
2139 if (!this.isActionBoxMenuActive) { 2091 if (!this.isActionBoxMenuActive) {
2140 if (this.isAuthTypeOnlineSignIn) { 2092 if (this.isAuthTypeOnlineSignIn) {
2141 this.showSigninUI(); 2093 this.showSigninUI();
2142 } else if (this.isAuthTypeUserClick && this.userClickAuthAllowed_) { 2094 } else if (this.isAuthTypeUserClick && this.userClickAuthAllowed_) {
2143 // Note that this.userClickAuthAllowed_ is set in mouse down event 2095 // Note that this.userClickAuthAllowed_ is set in mouse down event
2144 // handler. 2096 // handler.
2145 this.parentNode.setActivatedPod(this); 2097 this.parentNode.setActivatedPod(this);
2146 } else if (this.pinKeyboard && 2098 } else if (this.pinKeyboard &&
2147 e.target == this.pinKeyboard.submitButton) { 2099 e.target == this.pinKeyboard.submitButton) {
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
2400 2352
2401 /** @override */ 2353 /** @override */
2402 handleClickOnPod_: function(e) { 2354 handleClickOnPod_: function(e) {
2403 if (this.parentNode.disabled) 2355 if (this.parentNode.disabled)
2404 return; 2356 return;
2405 2357
2406 if (this.getPodStyle() != UserPod.Style.LARGE) { 2358 if (this.getPodStyle() != UserPod.Style.LARGE) {
2407 $('pod-row').switchMainPod(this); 2359 $('pod-row').switchMainPod(this);
2408 return; 2360 return;
2409 } 2361 }
2362 Oobe.clearErrors();
2410 2363
2411 this.parentNode.focusPod(this); 2364 this.parentNode.focusPod(this);
2412 this.parentNode.setActivatedPod(this, e); 2365 this.parentNode.setActivatedPod(this, e);
2413 // Prevent default so that we don't trigger 'focus' event. 2366 // Prevent default so that we don't trigger 'focus' event.
2414 e.preventDefault(); 2367 e.preventDefault();
2415 }, 2368 },
2416 2369
2417 /** 2370 /**
2418 * Updates the display name shown on the pod. 2371 * Updates the display name shown on the pod.
2419 * @param {string} displayName The new display name 2372 * @param {string} displayName The new display name
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after
2861 2814
2862 // True to show app pods along with user pods. 2815 // True to show app pods along with user pods.
2863 shouldShowApps_: true, 2816 shouldShowApps_: true,
2864 2817
2865 // Array of users that are shown (public/supervised/regular). 2818 // Array of users that are shown (public/supervised/regular).
2866 users_: [], 2819 users_: [],
2867 2820
2868 // If we're in Touch View mode. 2821 // If we're in Touch View mode.
2869 touchViewEnabled_: false, 2822 touchViewEnabled_: false,
2870 2823
2824 // If testing mode is enabled.
2825 testingModeEnabled_: false,
2826
2871 /** @override */ 2827 /** @override */
2872 decorate: function() { 2828 decorate: function() {
2873 // Event listeners that are installed for the time period during which 2829 // Event listeners that are installed for the time period during which
2874 // the element is visible. 2830 // the element is visible.
2875 this.listeners_ = { 2831 this.listeners_ = {
2876 focus: [this.handleFocus_.bind(this), true /* useCapture */], 2832 focus: [this.handleFocus_.bind(this), true /* useCapture */],
2877 click: [this.handleClick_.bind(this), true], 2833 click: [this.handleClick_.bind(this), true],
2878 mousemove: [this.handleMouseMove_.bind(this), false], 2834 mousemove: [this.handleMouseMove_.bind(this), false],
2879 keydown: [this.handleKeyDown.bind(this), false] 2835 keydown: [this.handleKeyDown.bind(this), false]
2880 }; 2836 };
(...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after
3496 var pod = this.getPodWithUsername_(userID); 3452 var pod = this.getPodWithUsername_(userID);
3497 if (pod != null) 3453 if (pod != null)
3498 pod.populateKeyboardSelect(locale, list); 3454 pod.populateKeyboardSelect(locale, list);
3499 }, 3455 },
3500 3456
3501 /** 3457 /**
3502 * Called when window was resized. The two common use cases are changing 3458 * Called when window was resized. The two common use cases are changing
3503 * screen orientation and showing the virtual keyboard. 3459 * screen orientation and showing the virtual keyboard.
3504 */ 3460 */
3505 onWindowResize: function() { 3461 onWindowResize: function() {
3506 var screen = document.querySelector('#scroll-container');
3507 var clientArea = document.querySelector('#inner-container');
3508 if (Oobe.getInstance().virtualKeyboardShown) {
3509 // Edge case: when virtual keyboard is shown, although the screen size
3510 // is reduced properly, the size of the outer container remains the
3511 // same because its min-height is applied. Users can scroll the screen
3512 // upward and see empty areas beyond the pod row and the scroll bar,
3513 // which should be avoided.
3514 // This is a hacky solution: we can make the scroll container hide
3515 // the overflow area and manully position the client area.
3516 screen.style.overflowY = "hidden";
3517 clientArea.style.position = "absolute";
3518 clientArea.style.left = cr.ui.toCssPx(0);
3519 clientArea.style.top = cr.ui.toCssPx(0);
3520 } else {
3521 // Sets the values to default when virtual keyboard is not shown.
3522 screen.style.overflowY = "auto";
3523 clientArea.style.position = "relative";
3524 }
3525 this.placePods_(); 3462 this.placePods_();
3526 }, 3463 },
3527 3464
3528 /** 3465 /**
3529 * Returns width of podrow having |columns| number of columns.
3530 * @private
3531 */
3532 columnsToWidth_: function(columns) {
3533 var isDesktopUserManager = Oobe.getInstance().displayType ==
3534 DISPLAY_TYPE.DESKTOP_USER_MANAGER;
3535 var margin = isDesktopUserManager ? DESKTOP_MARGIN_BY_COLUMNS[columns] :
3536 MARGIN_BY_COLUMNS[columns];
3537 var rowPadding = isDesktopUserManager ? DESKTOP_ROW_PADDING :
3538 POD_ROW_PADDING;
3539 return 2 * rowPadding + columns * this.userPodWidth_ +
3540 (columns - 1) * margin;
3541 },
3542
3543 /**
3544 * Returns height of podrow having |rows| number of rows.
3545 * @private
3546 */
3547 rowsToHeight_: function(rows) {
3548 var isDesktopUserManager = Oobe.getInstance().displayType ==
3549 DISPLAY_TYPE.DESKTOP_USER_MANAGER;
3550 var rowPadding = isDesktopUserManager ? DESKTOP_ROW_PADDING :
3551 POD_ROW_PADDING;
3552 return 2 * rowPadding + rows * this.userPodHeight_;
3553 },
3554
3555 /**
3556 * Calculates number of columns and rows that podrow should have in order to
3557 * hold as much its pods as possible for current screen size. Also it tries
3558 * to choose layout that looks good.
3559 * @return {{columns: number, rows: number}}
3560 */
3561 calculateLayout_: function() {
3562 var preferredColumns = this.pods.length < COLUMNS.length ?
3563 COLUMNS[this.pods.length] : COLUMNS[COLUMNS.length - 1];
3564 var maxWidth = Oobe.getInstance().clientAreaSize.width;
3565 var columns = preferredColumns;
3566 while (maxWidth < this.columnsToWidth_(columns) && columns > 1)
3567 --columns;
3568 var rows = Math.floor((this.pods.length - 1) / columns) + 1;
3569 if (getComputedStyle(
3570 $('signin-banner'), null).getPropertyValue('display') != 'none') {
3571 rows = Math.min(rows, MAX_NUMBER_OF_ROWS_UNDER_SIGNIN_BANNER);
3572 }
3573 if (!Oobe.getInstance().newDesktopUserManager) {
3574 var maxHeigth = Oobe.getInstance().clientAreaSize.height;
3575 while (maxHeigth < this.rowsToHeight_(rows) && rows > 1)
3576 --rows;
3577 }
3578 // One more iteration if it's not enough cells to place all pods.
3579 while (maxWidth >= this.columnsToWidth_(columns + 1) &&
3580 columns * rows < this.pods.length &&
3581 columns < MAX_NUMBER_OF_COLUMNS) {
3582 ++columns;
3583 }
3584 return {columns: columns, rows: rows};
3585 },
3586
3587 /**
3588 * Places pods onto their positions in pod grid matching the new design. 3466 * Places pods onto their positions in pod grid matching the new design.
3589 * @private 3467 * @private
3590 */ 3468 */
3591 placePods_: function() { 3469 placePods_: function() {
3592 var pods = this.pods; 3470 var pods = this.pods;
3593 if (pods.length == 0) { 3471 if (pods.length == 0) {
3594 console.error('Attempt to place pods for an empty pod list.'); 3472 console.error('Attempt to place pods for an empty pod list.');
3595 return; 3473 return;
3596 } 3474 }
3597 // Append all pods to their proper parents. Small pods have parent other 3475 // Appends all pods to their proper parents. Small pods have parent other
3598 // than the pod row. The pods were all initialized with the pow row as a 3476 // than the pod row. The pods were all initialized with the pow row as a
3599 // temporary parent, which is intended to ensure that all event listeners 3477 // temporary parent, which is intended to ensure that all event listeners
3600 // work properly. If the main pod already exists, it means we are in the 3478 // work properly. If the main pod already exists, it means we are in the
3601 // process of resizing the window, then there is no need to change parents 3479 // process of resizing the window, then there is no need to change parents
3602 // of any pod. 3480 // of any pod.
3603 if (!this.mainPod_) { 3481 if (!this.mainPod_) {
3604 this.mainPod_ = this.preselectedPod; 3482 this.mainPod_ = this.preselectedPod;
3605 this.appendPodsToParents(); 3483 this.appendPodsToParents_();
3606 } 3484 }
3607 this.restoreInitialStates_(); 3485 this.restoreInitialStates_();
3608 if (Oobe.getInstance().virtualKeyboardShown) { 3486 this.hideEmptyArea_();
3487 // Clear error bubbles whenever pod placement is happening, i.e., after
3488 // orientation change, showing or hiding virtual keyboard, and user
3489 // removal.
3490 Oobe.clearErrors();
3491
3492 if (this.isScreenShrinked_()) {
3609 // When virtual keyboard is shown, the account picker should occupy 3493 // When virtual keyboard is shown, the account picker should occupy
3610 // all the remaining screen. Screen size was already updated to exclude 3494 // all the remaining screen. Screen size was already updated to exclude
3611 // the virtual keyboard. 3495 // the virtual keyboard.
3612 this.parentNode.setPreferredSize( 3496 this.parentNode.setPreferredSize(this.screenSize.width,
3613 this.screenSize.width, 3497 this.screenSize.height);
3614 this.screenSize.height);
3615 } else { 3498 } else {
3616 // Make sure not to block the header bar when virtual keyboard is absent . 3499 // Make sure not to block the header bar when virtual keyboard is absent .
3617 this.parentNode.setPreferredSize( 3500 this.parentNode.setPreferredSize(
3618 Oobe.getInstance().clientAreaSize.width, 3501 Oobe.getInstance().clientAreaSize.width,
3619 Oobe.getInstance().clientAreaSize.height); 3502 Oobe.getInstance().clientAreaSize.height);
3620 } 3503 }
jdufault 2017/05/31 17:13:21 nit: drop whitespace
Wenzhao (Colin) Zang 2017/05/31 18:50:16 Done.
3621 3504
3622 if (pods.length == 1) { 3505 if (pods.length == 1) {
3623 this.placeSinglePod_(); 3506 this.placeSinglePod_();
3624 } else if (pods.length == POD_ROW_LIMIT) { 3507 } else if (pods.length == POD_ROW_LIMIT) {
3625 this.placePodsOnPodRow_(); 3508 this.placePodsOnPodRow_();
3626 } else { 3509 } else {
3627 this.placePodsOnContainer_(); 3510 this.placePodsOnContainer_();
3628 } 3511 }
3629 Oobe.getInstance().updateScreenSize(this.parentNode); 3512 Oobe.getInstance().updateScreenSize(this.parentNode);
3630 this.updatePodNameArea(); 3513 this.updatePodNameArea_();
3631 }, 3514 },
3632 3515
3633 /** 3516 /**
3634 * Append pods to proper parents. Called each time before pod placement. 3517 * Appends pods to proper parents. Called each time before pod placement.
3635 * @private 3518 * @private
3636 */ 3519 */
3637 appendPodsToParents: function() { 3520 appendPodsToParents_: function() {
3638 var pods = this.pods; 3521 var pods = this.pods;
3639 // Pod count may have changed, so the placement method may change 3522 // Pod count may have changed, so the placement method may change
3640 // accordingly. Therefore, always remove all pods from their current 3523 // accordingly. Therefore, always remove all pods from their current
3641 // parents first. 3524 // parents first.
3642 for (var pod of pods) { 3525 for (var pod of pods) {
3643 pod.parentNode.removeChild(pod); 3526 pod.parentNode.removeChild(pod);
3644 } 3527 }
3645 if (pods.length <= POD_ROW_LIMIT) { 3528 if (pods.length <= POD_ROW_LIMIT) {
3646 for (var pod of pods) { 3529 for (var pod of pods) {
3647 this.appendChild(pod); 3530 this.appendChild(pod);
3648 } 3531 }
3649 } else { 3532 } else {
3650 // When the user count exceeds the limit (currently set to 2), only the 3533 // When the user count exceeds the limit (currently set to 2), only the
3651 // main pod still has pow row as parent, all other pods should be 3534 // main pod still has pow row as parent, all other pods should be
3652 // appended to the container with scroll bar. 3535 // appended to the container with scroll bar.
3653 for (var pod of pods) { 3536 for (var pod of pods) {
3654 if (pod == this.mainPod_) { 3537 if (pod == this.mainPod_)
3655 this.appendChild(pod); 3538 this.appendChild(pod);
3656 } else { 3539 else
3657 this.smallPodsContainer.appendChild(pod); 3540 this.smallPodsContainer.appendChild(pod);
3658 }
3659 } 3541 }
3660 } 3542 }
3661 }, 3543 },
3662 3544
3663 /** 3545 /**
3546 * Makes inner container unscrollable and hides the bottom empty area
3547 * when virtual keyboard is shown.
3548 * @private
3549 */
3550 hideEmptyArea_: function() {
3551 var screen = document.querySelector('#scroll-container');
3552 var clientArea = document.querySelector('#inner-container');
3553 if (this.isScreenShrinked_()) {
3554 // When virtual keyboard is shown, although the screen size
3555 // is reduced properly, the size of the outer container remains the
jdufault 2017/05/31 17:13:21 Do we need the min-height on the outer container?
Wenzhao (Colin) Zang 2017/05/31 18:50:16 According to previous comments I found, the min-he
jdufault 2017/05/31 19:02:36 I'd be surprised if we ever want to enable that. T
3556 // same because its min-height is applied. Users can scroll the screen
3557 // upward and see empty areas beyond the pod row and the scroll bar,
3558 // which should be avoided.
3559 // This is a hacky solution: we can make the scroll container hide
3560 // the overflow area and manully position the client area.
3561 // We used to check Oobe.getInstance().virtualKeyboardShown directly
3562 // instead of the screen size, but there were occasional bugs because
3563 // that value may not be updated yet when we reach here.
3564 screen.style.overflowY = "hidden";
3565 clientArea.style.position = "absolute";
3566 clientArea.style.left = cr.ui.toCssPx(0);
3567 clientArea.style.top = cr.ui.toCssPx(0);
3568 } else {
3569 // Sets the values to default when virtual keyboard is not shown.
3570 screen.style.overflowY = "auto";
3571 clientArea.style.position = "relative";
3572 }
3573 },
3574
3575 /**
3664 * Called when there is one user pod. 3576 * Called when there is one user pod.
3665 * @private 3577 * @private
3666 */ 3578 */
3667 placeSinglePod_: function() { 3579 placeSinglePod_: function() {
3668 this.mainPod_.setPodStyle(UserPod.Style.LARGE); 3580 this.mainPod_.setPodStyle(UserPod.Style.LARGE);
3669 this.mainPod_.left = (this.screenSize.width - CROS_POD_WIDTH) / 2; 3581 this.mainPod_.left = (this.screenSize.width - CROS_POD_WIDTH) / 2;
3670 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2; 3582 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
3671 }, 3583 },
3672 3584
3673 /** 3585 /**
3674 * Called when there are two users pods. 3586 * Called when there are two users pods.
3675 * @private 3587 * @private
3676 */ 3588 */
3677 placePodsOnPodRow_: function() { 3589 placePodsOnPodRow_: function() {
3678 // Both pods have large size and are placed adjacently. 3590 // Both pods have large size and are placed adjacently.
3679 var secondPod = 3591 var secondPod =
3680 this.pods[0] == this.mainPod_ ? this.pods[1] : this.pods[0]; 3592 this.pods[0] == this.mainPod_ ? this.pods[1] : this.pods[0];
3681 this.mainPod_.setPodStyle(UserPod.Style.LARGE); 3593 this.mainPod_.setPodStyle(UserPod.Style.LARGE);
3682 secondPod.setPodStyle(UserPod.Style.LARGE); 3594 secondPod.setPodStyle(UserPod.Style.LARGE);
3683 3595
3684 var DOUBLE_PODS_PADDING = this.isPortraitMode() ? 32 : 118; 3596 var DOUBLE_PODS_PADDING = this.isPortraitMode_() ? 32 : 118;
3685 var leftPadding = (this.screenSize.width - (CROS_POD_WIDTH * 2 + DOUBLE_PO DS_PADDING)) / 2; 3597 var leftPadding = (this.screenSize.width - (CROS_POD_WIDTH * 2 + DOUBLE_PO DS_PADDING)) / 2;
3686 // Start actual positioning. 3598 // Start actual positioning.
3687 this.mainPod_.left = leftPadding; 3599 this.mainPod_.left = leftPadding;
3688 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2; 3600 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
3689 secondPod.left = leftPadding + CROS_POD_WIDTH + DOUBLE_PODS_PADDING; 3601 secondPod.left = leftPadding + CROS_POD_WIDTH + DOUBLE_PODS_PADDING;
3690 secondPod.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2; 3602 secondPod.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
3691 }, 3603 },
3692 3604
3693 /** 3605 /**
3694 * Called when there are more than two user pods. 3606 * Called when there are more than two user pods.
3695 * @private 3607 * @private
3696 */ 3608 */
3697 placePodsOnContainer_: function() { 3609 placePodsOnContainer_: function() {
3698 this.smallPodsContainer.hidden = false; 3610 this.smallPodsContainer.hidden = false;
3699 var pods = this.pods; 3611 var pods = this.pods;
3700 if ((pods.length > LANDSCAPE_MODE_LIMIT && !this.isPortraitMode()) || 3612 if ((pods.length > LANDSCAPE_MODE_LIMIT && !this.isPortraitMode_()) ||
3701 (pods.length > PORTRAIT_MODE_LIMIT && this.isPortraitMode())) { 3613 (pods.length > PORTRAIT_MODE_LIMIT && this.isPortraitMode_())) {
3702 // If the pod count exceeds limits, they should be in extra small size 3614 // If the pod count exceeds limits, they should be in extra small size
3703 // and the container will become scrollable. 3615 // and the container will become scrollable.
3704 this.placePodsOnScrollableContainer_(); 3616 this.placePodsOnScrollableContainer_();
3705 return; 3617 return;
3706 } 3618 }
3707 this.mainPod_.setPodStyle(UserPod.Style.LARGE); 3619 this.mainPod_.setPodStyle(UserPod.Style.LARGE);
3708 for (var pod of pods) { 3620 for (var pod of pods) {
3709 if (pod != this.mainPod_) { 3621 if (pod != this.mainPod_) {
3710 // All pods except the main one must be set to the small style. 3622 // All pods except the main one must be set to the small style.
3711 pod.setPodStyle(UserPod.Style.SMALL); 3623 pod.setPodStyle(UserPod.Style.SMALL);
3712 } 3624 }
3713 } 3625 }
3714 // The size of the smallPodsContainer must be updated to avoid overflow, 3626 // The size of the smallPodsContainer must be updated to avoid overflow,
3715 // otherwise unnecessary scroll bar will show up. 3627 // otherwise unnecessary scroll bar will show up.
3716 this.smallPodsContainer.style.height = 3628 this.smallPodsContainer.style.height =
3717 cr.ui.toCssPx(this.screenSize.height); 3629 cr.ui.toCssPx(this.screenSize.height);
3718 this.smallPodsContainer.style.width = cr.ui.toCssPx(CROS_SMALL_POD_WIDTH); 3630 this.smallPodsContainer.style.width = cr.ui.toCssPx(CROS_SMALL_POD_WIDTH);
3719 3631
3720 var LEFT_PADDING = this.isPortraitMode() ? 0 : 98; 3632 var LEFT_PADDING = this.isPortraitMode_() ? 0 : 98;
3721 var MIDDLE_PADDING = this.isPortraitMode() ? 84 : 220; 3633 var MIDDLE_PADDING = this.isPortraitMode_() ? 84 : 220;
3722 var contentsWidth = LEFT_PADDING + 3634 var contentsWidth = LEFT_PADDING +
3723 CROS_POD_WIDTH + MIDDLE_PADDING + CROS_SMALL_POD_WIDTH; 3635 CROS_POD_WIDTH + MIDDLE_PADDING + CROS_SMALL_POD_WIDTH;
3724 var blankWidth = this.screenSize.width - contentsWidth; 3636 var blankWidth = this.screenSize.width - contentsWidth;
3725 var actualLeftPadding = LEFT_PADDING; 3637 var actualLeftPadding = LEFT_PADDING;
3726 actualLeftPadding += this.isPortraitMode() ? blankWidth * 2 / 3: 3638 actualLeftPadding += this.isPortraitMode_() ? blankWidth * 2 / 3:
3727 blankWidth / 2; 3639 blankWidth / 2;
3728 var SMALL_POD_PADDING = 54; 3640 var SMALL_POD_PADDING = 54;
3729 var actualSmallPodPadding = SMALL_POD_PADDING; 3641 var actualSmallPodPadding = SMALL_POD_PADDING;
3730 var smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT + 3642 var smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT +
3731 (pods.length - 2) * actualSmallPodPadding; 3643 (pods.length - 2) * actualSmallPodPadding;
3732 if (smallPodsTotalHeight > this.screenSize.height) { 3644 if (smallPodsTotalHeight > this.screenSize.height) {
3733 // Edge case: when the virtual keyboard is present, the total height of 3645 // Edge case: when the virtual keyboard is present, the total height of
3734 // the smallPodsContainer may exceed the screen height. Decrease the 3646 // the smallPodsContainer may exceed the screen height. Decrease the
3735 // padding among small pods according to the design spec. 3647 // padding among small pods according to the design spec.
3736 actualSmallPodPadding = 32; 3648 actualSmallPodPadding = 32;
3737 smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT + 3649 smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT +
(...skipping 29 matching lines...) Expand all
3767 this.smallPodsContainer.classList.add('scroll'); 3679 this.smallPodsContainer.classList.add('scroll');
3768 var pods = this.pods; 3680 var pods = this.pods;
3769 this.mainPod_.setPodStyle(UserPod.Style.LARGE); 3681 this.mainPod_.setPodStyle(UserPod.Style.LARGE);
3770 for (var pod of pods) { 3682 for (var pod of pods) {
3771 if (pod != this.mainPod_) { 3683 if (pod != this.mainPod_) {
3772 // All pods except the main one must be set to the extra small style. 3684 // All pods except the main one must be set to the extra small style.
3773 pod.setPodStyle(UserPod.Style.EXTRA_SMALL); 3685 pod.setPodStyle(UserPod.Style.EXTRA_SMALL);
3774 } 3686 }
3775 } 3687 }
3776 3688
3777 var SCROLL_LEFT_PADDING = this.isPortraitMode() ? 46 : 72; 3689 var SCROLL_LEFT_PADDING = this.isPortraitMode_() ? 46 : 72;
3778 var SCROLL_RIGHT_PADDING = this.isPortraitMode() ? 12 : 72; 3690 var SCROLL_RIGHT_PADDING = this.isPortraitMode_() ? 12 : 72;
3779 // The offsetWidth of the smallPodsContainer. 3691 // The offsetWidth of the smallPodsContainer.
3780 var scrollAreaWidth = SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH + 3692 var scrollAreaWidth = SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH +
3781 SCROLL_RIGHT_PADDING; 3693 SCROLL_RIGHT_PADDING;
3782 var mainPodPadding = (this.screenSize.width - 3694 var mainPodPadding = (this.screenSize.width -
3783 scrollAreaWidth - CROS_POD_WIDTH) / 2; 3695 scrollAreaWidth - CROS_POD_WIDTH) / 2;
3784 var SCROLL_TOP_PADDING = this.isPortraitMode() ? 66 : 72; 3696 var SCROLL_TOP_PADDING = this.isPortraitMode_() ? 66 : 72;
3785 var EXTRA_SMALL_POD_PADDING = 32; 3697 var EXTRA_SMALL_POD_PADDING = 32;
3786 // Start positioning of the main pod and the smallPodsContainer. 3698 // Start positioning of the main pod and the smallPodsContainer.
3787 this.mainPod_.left = mainPodPadding; 3699 this.mainPod_.left = mainPodPadding;
3788 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2; 3700 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
3789 this.smallPodsContainer.style.left = 3701 this.smallPodsContainer.style.left =
3790 cr.ui.toCssPx(mainPodPadding * 2 + CROS_POD_WIDTH); 3702 cr.ui.toCssPx(mainPodPadding * 2 + CROS_POD_WIDTH);
3791 this.smallPodsContainer.style.top = cr.ui.toCssPx(0); 3703 this.smallPodsContainer.style.top = cr.ui.toCssPx(0);
3792 3704
3793 // Precalculate the total height of the scrollable container and check if 3705 // Precalculate the total height of the scrollable container and check if
3794 // it indeed exceeds the screen height. 3706 // it indeed exceeds the screen height.
(...skipping 15 matching lines...) Expand all
3810 // before allowing the container to overflow and show the scroll bar. 3722 // before allowing the container to overflow and show the scroll bar.
3811 var actualTopPadding = SCROLL_TOP_PADDING; 3723 var actualTopPadding = SCROLL_TOP_PADDING;
3812 if ((this.screenSize.height - scrollHeight) / 2 > actualTopPadding) { 3724 if ((this.screenSize.height - scrollHeight) / 2 > actualTopPadding) {
3813 // Edge case: the total height of the scrollable container does not 3725 // Edge case: the total height of the scrollable container does not
3814 // exceed the screen height (minus the neceesary padding), so the 3726 // exceed the screen height (minus the neceesary padding), so the
3815 // scroll bar will not appear. 3727 // scroll bar will not appear.
3816 // In this case, we still want to keep the extra small pod size and 3728 // In this case, we still want to keep the extra small pod size and
3817 // the overlay, but the top and bottom padding should be adjusted 3729 // the overlay, but the top and bottom padding should be adjusted
3818 // to ensure a symmetric layout. 3730 // to ensure a symmetric layout.
3819 actualTopPadding = (this.screenSize.height - scrollHeight) / 2; 3731 actualTopPadding = (this.screenSize.height - scrollHeight) / 2;
3820 } else if (!Oobe.getInstance().virtualKeyboardShown) { 3732 } else if (!this.isScreenShrinked_()) {
3821 // The scroll bar will definitely be shown if we reach here. A gradient 3733 // The scroll bar will definitely be shown if we reach here. A gradient
3822 // mask is applied to avoid blocking the header bar if the virtual 3734 // mask is applied to avoid blocking the header bar if the virtual
3823 // keyboard is not shown. When the keyboard is shown, there's no need 3735 // keyboard is not shown. When the keyboard is shown, there's no need
3824 // to add the mask and the original top padding value should be kept. 3736 // to add the mask and the original top padding value should be kept.
3825 actualTopPadding = SCROLL_MASK_HEIGHT; 3737 actualTopPadding = SCROLL_MASK_HEIGHT;
3826 this.showScrollMask(); 3738 this.showScrollMask_();
3827 } 3739 }
3828 3740
3829 // Start positioning of the small pods inside the smallPodsContainer. 3741 // Start positioning of the small pods inside the smallPodsContainer.
3830 var topPadding = actualTopPadding; 3742 var topPadding = actualTopPadding;
3831 var lastPod = undefined; 3743 var lastPod = undefined;
3832 for (var pod of pods) { 3744 for (var pod of pods) {
3833 if (pod == this.mainPod_) { 3745 if (pod == this.mainPod_) {
3834 continue; 3746 continue;
3835 } 3747 }
3836 pod.left = SCROLL_LEFT_PADDING; 3748 pod.left = SCROLL_LEFT_PADDING;
(...skipping 18 matching lines...) Expand all
3855 document.querySelector('.small-pod-container-mask').hidden = true; 3767 document.querySelector('.small-pod-container-mask').hidden = true;
3856 document.querySelector('.small-pod-container-mask.rotate').hidden = true; 3768 document.querySelector('.small-pod-container-mask.rotate').hidden = true;
3857 this.smallPodsContainer.classList.remove('scroll'); 3769 this.smallPodsContainer.classList.remove('scroll');
3858 var pods = this.pods; 3770 var pods = this.pods;
3859 for (var pod of pods) { 3771 for (var pod of pods) {
3860 // There is a chance that one of the pods has a bottom padding, so 3772 // There is a chance that one of the pods has a bottom padding, so
3861 // reset all of them to be safe. This is because if the pod was at 3773 // reset all of them to be safe. This is because if the pod was at
3862 // the last position in the scrollable container, a bottom padding 3774 // the last position in the scrollable container, a bottom padding
3863 // was added to ensure a symmetric layout. 3775 // was added to ensure a symmetric layout.
3864 pod.style.paddingBottom = cr.ui.toCssPx(0); 3776 pod.style.paddingBottom = cr.ui.toCssPx(0);
3777 // Remove the switch animation that might be added earlier.
3778 pod.imageElement.classList.remove('switch-image-animation');
3779 pod.smallPodImageElement.classList.remove('switch-image-animation');
3865 } 3780 }
3866 }, 3781 },
3867 3782
3868 /** 3783 /**
3869 * Check if the screen is in portrait mode. 3784 * Checks if the screen is in portrait mode.
3870 * @return {boolean} True if in portrait mode. 3785 * @return {boolean} True if in portrait mode.
3871 */ 3786 */
3872 isPortraitMode: function() { 3787 isPortraitMode_: function() {
3873 return this.screenSize.width < 3788 return this.screenSize.width < this.screenSize.height;
3874 this.screenSize.height; 3789 },
3790
3791 /**
3792 * Checks if the screen is shrinked, e.g., when showing virtual keyboard.
3793 * @return {boolean} True if the screen is shrinked.
3794 */
3795 isScreenShrinked_: function() {
3796 return this.screenSize.height <= Oobe.getInstance().clientAreaSize.height;
jdufault 2017/05/31 17:13:21 Why not use virtualKeyboardShown? Can you document
Wenzhao (Colin) Zang 2017/05/31 18:50:16 AFAIK there's no additional case, but based on my
jdufault 2017/05/31 19:02:36 Okay. Can you add a comment?
3875 }, 3797 },
3876 3798
3877 /** 3799 /**
3878 * Called when scroll bar is shown and we need a mask for the header bar. 3800 * Called when scroll bar is shown and we need a mask for the header bar.
3879 * @private 3801 * @private
3880 */ 3802 */
3881 showScrollMask: function() { 3803 showScrollMask_: function() {
3882 var topMask = document.querySelector('.small-pod-container-mask'); 3804 var topMask = document.querySelector('.small-pod-container-mask');
3883 topMask.hidden = false; 3805 topMask.hidden = false;
3884 topMask.style.left = this.smallPodsContainer.style.left; 3806 topMask.style.left = this.smallPodsContainer.style.left;
3885 topMask.style.width = this.smallPodsContainer.style.width; 3807 topMask.style.width = this.smallPodsContainer.style.width;
3886 // The bottom mask is a rotation of the top mask. 3808 // The bottom mask is a rotation of the top mask.
3887 var bottomMask = 3809 var bottomMask =
3888 document.querySelector('.small-pod-container-mask.rotate'); 3810 document.querySelector('.small-pod-container-mask.rotate');
3889 bottomMask.hidden = false; 3811 bottomMask.hidden = false;
3890 bottomMask.style.left = this.smallPodsContainer.style.left; 3812 bottomMask.style.left = this.smallPodsContainer.style.left;
3891 bottomMask.style.width = this.smallPodsContainer.style.width; 3813 bottomMask.style.width = this.smallPodsContainer.style.width;
3892 // The bottom mask should overlap with the header bar, and its z-index 3814 // The bottom mask should overlap with the header bar, and its z-index
3893 // is chosen to ensure it does not block users from using the header bar. 3815 // is chosen to ensure it does not block users from using the header bar.
3894 bottomMask.style.top = cr.ui.toCssPx( 3816 bottomMask.style.top = cr.ui.toCssPx(this.screenSize.height - SCROLL_MASK_ HEIGHT);
3895 this.screenSize.height -
3896 SCROLL_MASK_HEIGHT);
3897 }, 3817 },
3898 3818
3899 /** 3819 /**
3900 * Makes sure that user name on each large pod is centered and extra long 3820 * Makes sure that:
3901 * name does not exceed max width. Names on small pods do not need to be 3821 * 1) User name on each large pod is centered.
3902 * dynamically updated. 3822 * 2) Extra long names don't exceed maximum pod width.
3823 * 3) Action box menus are either left-aligned or right-aligned with
3824 * the drop down button.
3903 * @private 3825 * @private
3904 */ 3826 */
3905 updatePodNameArea: function() { 3827 updatePodNameArea_: function() {
3906 this.querySelectorAll('.name-container').forEach(function(nameArea) { 3828 var pods = this.pods;
3907 var nameElement = nameArea.querySelector('.name'); 3829 for (var pod of pods) {
3908 var leftMargin = (CROS_POD_WIDTH - nameElement.offsetWidth) / 2; 3830 if (pods.length > POD_ROW_LIMIT && pod != this.mainPod_)
3831 continue;
3832 var nameArea = pod.querySelector('.name-container');
3833 var leftMargin = (CROS_POD_WIDTH - pod.nameElement.offsetWidth) / 2;
3909 if (leftMargin > 0) 3834 if (leftMargin > 0)
3910 nameArea.style.left = cr.ui.toCssPx(leftMargin); 3835 nameArea.style.left = cr.ui.toCssPx(leftMargin);
3911 else 3836 else {
3912 nameElement.style.width = cr.ui.toCssPx(CROS_POD_WIDTH); 3837 pod.nameElement.style.width = cr.ui.toCssPx(CROS_POD_WIDTH);
3913 }); 3838 nameArea.style.left = cr.ui.toCssPx(0);
3839 }
3840 // Update action box menu position to ensure it doesn't overlap with
3841 // elements outside the pod.
3842 var actionBoxMenu = pod.querySelector('.action-box-menu');
3843 var actionBoxButton = pod.querySelector('.action-box-button');
3844 var MENU_TOP_PADDING = 7;
3845 actionBoxMenu.style.top = cr.ui.toCssPx(actionBoxButton.offsetHeight + M ENU_TOP_PADDING);
3846 if (this.isPortraitMode_() && pods.length > 1) {
3847 // Confine the menu inside the pod when it may overlap with outside
3848 // elements.
3849 actionBoxMenu.style.left = "auto";
3850 actionBoxMenu.style.right = cr.ui.toCssPx(0);
3851 } else {
3852 actionBoxMenu.style.left = cr.ui.toCssPx(pod.nameElement.offsetWidth + actionBoxButton.style.marginLeft);
3853 actionBoxMenu.style.right = "auto";
3854 }
3855 // Add ripple animation.
3856 var actionBoxRippleEffect = pod.querySelector('.action-box-button.ripple -circle');
3857 actionBoxRippleEffect.style.left = actionBoxMenu.style.left;
3858 actionBoxRippleEffect.style.top = cr.ui.toCssPx(actionBoxButton.style.ma rginTop);
3859 }
3914 }, 3860 },
3915 3861
3916 /** 3862 /**
3917 * Called when a small or extra small pod is clicked to trigger the switch 3863 * Called when a small or extra small pod is clicked to trigger the switch
3918 * with the main pod. 3864 * with the main pod.
3919 */ 3865 */
3920 switchMainPod: function(pod) { 3866 switchMainPod: function(pod) {
3921 if (this.disabled) { 3867 if (this.disabled) {
3922 console.error('Cannot change main pod while sign-in UI is disabled.'); 3868 console.error('Cannot change main pod while sign-in UI is disabled.');
3923 return; 3869 return;
3924 } 3870 }
3925 if (!this.mainPod_) { 3871 if (!this.mainPod_) {
3926 console.error('Attempt to switch a non-existing main pod.'); 3872 console.error('Attempt to switch a non-existing main pod.');
3927 return; 3873 return;
3928 } 3874 }
3929 // Find the index of the small pod. 3875 // Find the index of the small pod.
3930 var insert = 0; 3876 var insert = 0;
3931 var children = pod.parentNode.children; 3877 var children = pod.parentNode.children;
3932 while (insert < children.length && children[insert] != pod) 3878 while (insert < children.length && children[insert] != pod)
3933 insert++; 3879 insert++;
3934 if (insert >= children.length) { 3880 if (insert >= children.length) {
3935 console.error('Attempt to switch a non-existing small pod.'); 3881 console.error('Attempt to switch a non-existing small pod.');
3936 return; 3882 return;
3937 } 3883 }
3938 // Switch style of the two pods. 3884 // Switch style of the two pods.
3939 this.mainPod_.setPodStyle(pod.getPodStyle()); 3885 this.mainPod_.setPodStyle(pod.getPodStyle());
3940 pod.setPodStyle(UserPod.Style.LARGE); 3886 pod.setPodStyle(UserPod.Style.LARGE);
3887 // Add switch animation.
3888 this.mainPod_.smallPodImageElement.classList.add('switch-image-animation') ;
3889 pod.imageElement.classList.add('switch-image-animation');
3941 3890
3942 // Switch parent and position of the two pods. 3891 // Switch parent and position of the two pods.
3943 var left = pod.left; 3892 var left = pod.left;
3944 var top = pod.top; 3893 var top = pod.top;
3945 // Edge case: paddingBottom should be switched too because there's a 3894 // Edge case: paddingBottom should be switched too because there's a
3946 // chance that the small pod was at the end of the scrollable container 3895 // chance that the small pod was at the end of the scrollable container
3947 // and had a non-zero paddingBottom. 3896 // and had a non-zero paddingBottom.
3948 var paddingBottom = pod.style.paddingBottom; 3897 var paddingBottom = pod.style.paddingBottom;
3949 var parent = pod.parentNode; 3898 var parent = pod.parentNode;
3950 parent.removeChild(pod); 3899 parent.removeChild(pod);
3951 this.appendChild(pod); 3900 this.appendChild(pod);
3952 pod.left = this.mainPod_.left; 3901 pod.left = this.mainPod_.left;
3953 pod.top = this.mainPod_.top; 3902 pod.top = this.mainPod_.top;
3954 pod.style.paddingBottom = cr.ui.toCssPx(0); 3903 pod.style.paddingBottom = cr.ui.toCssPx(0);
3955 3904
3956 this.removeChild(this.mainPod_); 3905 this.removeChild(this.mainPod_);
3957 // It must have the same index with the original small pod, instead 3906 // It must have the same index with the original small pod, instead
3958 // of being appended as the last child, in order to maintain the 'Tab' 3907 // of being appended as the last child, in order to maintain the 'Tab'
3959 // order. 3908 // order.
3960 parent.insertBefore(this.mainPod_, children[insert]); 3909 parent.insertBefore(this.mainPod_, children[insert]);
3961 this.mainPod_.left = left; 3910 this.mainPod_.left = left;
3962 this.mainPod_.top = top; 3911 this.mainPod_.top = top;
3963 this.mainPod_.style.paddingBottom = paddingBottom; 3912 this.mainPod_.style.paddingBottom = paddingBottom;
3964 this.mainPod_ = pod; 3913 this.mainPod_ = pod;
3965 // Focus the new main pod. 3914 // The new main pod should already be focused but we need a focus update
3966 this.focusPod(this.mainPod_); 3915 // in order to focus on the input box.
3967 this.updatePodNameArea(); 3916 this.focusPod(this.mainPod_, true /* force */);
3917 this.updatePodNameArea_();
3968 }, 3918 },
3969 3919
3970 /** 3920 /**
3971 * Returns dimensions of screen including the header bar. 3921 * Returns dimensions of screen including the header bar.
3972 * @type {Object} 3922 * @type {Object}
3973 */ 3923 */
3974 get screenSize() { 3924 get screenSize() {
3975 var container = $('scroll-container'); 3925 var container = $('scroll-container');
3976 return {width: container.offsetWidth, height: container.offsetHeight}; 3926 return {width: container.offsetWidth, height: container.offsetHeight};
3977 }, 3927 },
3978 3928
3979 /** 3929 /**
3980 * Number of columns. 3930 * Displays a banner containing |message|. If the banner is already present
3981 * @type {?number} 3931 * this function updates the message in the banner.
3932 * @param {string} message Text to be displayed or empty to hide the banner.
3982 */ 3933 */
3983 set columns(columns) { 3934 showBannerMessage: function(message) {
3984 // Cannot use 'columns' here. 3935 var banner = $('signin-banner');
3985 this.setAttribute('ncolumns', columns); 3936 banner.textContent = message;
3986 }, 3937 banner.classList.toggle('message-set', !!message);
3987 get columns() { 3938 var bannerContainer = $('signin-banner-container1');
3988 return parseInt(this.getAttribute('ncolumns')); 3939 var BANNER_TOP_PADDING = this.isScreenShrinked_() ? 0 : 38;
3940 bannerContainer.style.top = cr.ui.toCssPx(this.mainPod_.top + CROS_POD_HEI GHT + BANNER_TOP_PADDING);
3941 if (this.pods.length <= POD_ROW_LIMIT)
3942 bannerContainer.style.left = cr.ui.toCssPx((this.screenSize.width - BANN ER_MESSAGE_WIDTH) / 2);
3943 else {
3944 var leftPadding = this.mainPod_.left - (BANNER_MESSAGE_WIDTH - CROS_POD_ WIDTH) / 2;
3945 bannerContainer.style.left = cr.ui.toCssPx(Math.max(leftPadding, 0));
3946 }
3989 }, 3947 },
3990 3948
3991 /** 3949 /**
3992 * Number of rows.
3993 * @type {?number}
3994 */
3995 set rows(rows) {
3996 // Cannot use 'rows' here.
3997 this.setAttribute('nrows', rows);
3998 },
3999 get rows() {
4000 return parseInt(this.getAttribute('nrows'));
4001 },
4002
4003 /**
4004 * Whether the pod is currently focused. 3950 * Whether the pod is currently focused.
4005 * @param {UserPod} pod Pod to check for focus. 3951 * @param {UserPod} pod Pod to check for focus.
4006 * @return {boolean} Pod focus status. 3952 * @return {boolean} Pod focus status.
4007 */ 3953 */
4008 isFocused: function(pod) { 3954 isFocused: function(pod) {
4009 return this.focusedPod_ == pod; 3955 return this.focusedPod_ == pod;
4010 }, 3956 },
4011 3957
4012 /** 3958 /**
4013 * Focuses a given user pod or clear focus when given null. 3959 * Focuses a given user pod or clear focus when given null.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
4072 // |opt_skipInputFocus| is true. When |multiProfilesPolicyApplied| 4018 // |opt_skipInputFocus| is true. When |multiProfilesPolicyApplied|
4073 // is false, it doesn't focus on the password input box by default. 4019 // is false, it doesn't focus on the password input box by default.
4074 podToFocus.focus(); 4020 podToFocus.focus();
4075 } 4021 }
4076 4022
4077 // focusPod() automatically loads wallpaper 4023 // focusPod() automatically loads wallpaper
4078 if (!podToFocus.user.isApp) 4024 if (!podToFocus.user.isApp)
4079 chrome.send('focusPod', [podToFocus.user.username]); 4025 chrome.send('focusPod', [podToFocus.user.username]);
4080 this.firstShown_ = false; 4026 this.firstShown_ = false;
4081 this.lastFocusedPod_ = podToFocus; 4027 this.lastFocusedPod_ = podToFocus;
4082 this.scrollFocusedPodIntoView();
4083 this.setUserPodFingerprintIcon( 4028 this.setUserPodFingerprintIcon(
4084 podToFocus.user.username, FINGERPRINT_STATES.DEFAULT); 4029 podToFocus.user.username, FINGERPRINT_STATES.DEFAULT);
4085 } else { 4030 } else {
4086 chrome.send('noPodFocused'); 4031 chrome.send('noPodFocused');
4087 } 4032 }
4088 this.insideFocusPod_ = false; 4033 this.insideFocusPod_ = false;
4089 }, 4034 },
4090 4035
4091 /** 4036 /**
4092 * Resets wallpaper to the last active user's wallpaper, if any. 4037 * Resets wallpaper to the last active user's wallpaper, if any.
(...skipping 14 matching lines...) Expand all
4107 /** 4052 /**
4108 * Sets currently activated pod. 4053 * Sets currently activated pod.
4109 * @param {UserPod} pod Pod to check for focus. 4054 * @param {UserPod} pod Pod to check for focus.
4110 * @param {Event} e Event object. 4055 * @param {Event} e Event object.
4111 */ 4056 */
4112 setActivatedPod: function(pod, e) { 4057 setActivatedPod: function(pod, e) {
4113 if (this.disabled) { 4058 if (this.disabled) {
4114 console.error('Cannot activate pod while sign-in UI is disabled.'); 4059 console.error('Cannot activate pod while sign-in UI is disabled.');
4115 return; 4060 return;
4116 } 4061 }
4062 // If testing mode is enabled and a positive integer was entered, abort
4063 // the activation process and start testing mode.
4064 if (pod && this.testingModeEnabled_) {
4065 var userCount = pod.passwordElement.value;
4066 if (parseInt(userCount) == userCount && userCount > 0) {
4067 this.showDummyUsersForTesting(userCount);
4068 return;
4069 }
4070 }
4117 if (pod && pod.activate(e)) 4071 if (pod && pod.activate(e))
4118 this.activatedPod_ = pod; 4072 this.activatedPod_ = pod;
4119 }, 4073 },
4120 4074
4121 /** 4075 /**
4076 * Used for testing only. Create the specified number of dummy users and
4077 * conveniently test the behaviors under different number of pods.
4078 * @param {number} count The number of users we want to test for.
4079 */
4080 showDummyUsersForTesting: function(count) {
jdufault 2017/05/31 17:13:21 Nice!
4081 if (!this.testingModeEnabled_) {
4082 console.error('Attempt to create dummy users when testing mode is disabl ed.');
4083 return;
4084 }
4085 var pods = this.pods;
4086 for (var pod of pods)
4087 pod.parentNode.removeChild(pod);
4088 var sampleUser = this.users_[0];
4089 var users = [];
4090 for (var i = 0; i < count; i++)
4091 users.push(sampleUser);
4092
4093 this.loadPods(users);
4094 },
4095
4096 /**
4122 * The pod of the signed-in user, if any; null otherwise. 4097 * The pod of the signed-in user, if any; null otherwise.
4123 * @type {?UserPod} 4098 * @type {?UserPod}
4124 */ 4099 */
4125 get lockedPod() { 4100 get lockedPod() {
4126 for (var i = 0, pod; pod = this.pods[i]; ++i) { 4101 for (var i = 0, pod; pod = this.pods[i]; ++i) {
4127 if (pod.user.signedIn) 4102 if (pod.user.signedIn)
4128 return pod; 4103 return pod;
4129 } 4104 }
4130 return null; 4105 return null;
4131 }, 4106 },
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
4228 for (var i = 0, pod; pod = this.pods[i]; ++i) 4203 for (var i = 0, pod; pod = this.pods[i]; ++i)
4229 pod.isActionBoxMenuActive = false; 4204 pod.isActionBoxMenuActive = false;
4230 } 4205 }
4231 4206
4232 // Clears focus if not clicked on a pod and if there's more than one pod. 4207 // Clears focus if not clicked on a pod and if there's more than one pod.
4233 var pod = findAncestorByClass(e.target, 'pod'); 4208 var pod = findAncestorByClass(e.target, 'pod');
4234 if ((!pod || pod.parentNode != this) && !this.alwaysFocusSinglePod) { 4209 if ((!pod || pod.parentNode != this) && !this.alwaysFocusSinglePod) {
4235 this.focusPod(); 4210 this.focusPod();
4236 } 4211 }
4237 4212
4238 if (pod) 4213 if (pod && pod.getPodStyle() == UserPod.Style.LARGE)
4239 pod.isActionBoxMenuHovered = true; 4214 pod.isActionBoxMenuHovered = true;
4240 4215
4241 // Return focus back to single pod. 4216 // Return focus back to single pod.
4242 if (this.alwaysFocusSinglePod && !pod) { 4217 if (this.alwaysFocusSinglePod && !pod) {
4243 if ($('login-header-bar').contains(e.target)) 4218 if ($('login-header-bar').contains(e.target))
4244 return; 4219 return;
4245 this.focusPod(this.focusedPod_, true /* force */); 4220 // If the click is outside the single pod, still focus on that pod
4221 // but do not focus on input box any more. This makes virtual keyboard
4222 // (if present) disappear.
4223 this.focusPod(this.focusedPod_, true /* force */, true /* opt_skipInputF ocus */);
jdufault 2017/05/31 17:13:21 nit: line length
Wenzhao (Colin) Zang 2017/05/31 18:50:16 Done.
4246 this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown'); 4224 this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown');
4247 this.focusedPod_.isActionBoxMenuHovered = false; 4225 this.focusedPod_.isActionBoxMenuHovered = false;
4248 } 4226 }
4249 }, 4227 },
4250 4228
4251 /** 4229 /**
4252 * Handler of mouse move event. 4230 * Handler of mouse move event.
4253 * @param {Event} e Click Event object. 4231 * @param {Event} e Click Event object.
4254 * @private 4232 * @private
4255 */ 4233 */
(...skipping 23 matching lines...) Expand all
4279 4257
4280 /** 4258 /**
4281 * Handles focus event. 4259 * Handles focus event.
4282 * @param {Event} e Focus Event object. 4260 * @param {Event} e Focus Event object.
4283 * @private 4261 * @private
4284 */ 4262 */
4285 handleFocus_: function(e) { 4263 handleFocus_: function(e) {
4286 if (this.disabled) 4264 if (this.disabled)
4287 return; 4265 return;
4288 if (e.target.parentNode == this) { 4266 if (e.target.parentNode == this) {
4289 // Focus on a pod 4267 // Handles focus event on a large pod.
4290 if (e.target.classList.contains('focused')) { 4268 if (e.target.classList.contains('focused')) {
4269 // Edge case: prevent input box from receiving unncessary focus
4270 // (thus hiding virtual keyboard) when remove user is clicked.
4271 if (e.target.isActionBoxMenuActive)
4272 return;
4291 if (!e.target.multiProfilesPolicyApplied) 4273 if (!e.target.multiProfilesPolicyApplied)
4292 e.target.focusInput(); 4274 e.target.focusInput();
4293 else 4275 else
4294 e.target.userTypeBubbleElement.classList.add('bubble-shown'); 4276 e.target.userTypeBubbleElement.classList.add('bubble-shown');
4295 } else 4277 } else
4296 this.focusPod(e.target); 4278 this.focusPod(e.target);
4297 return; 4279 return;
4298 } 4280 }
4299 4281
4300 // Small pods do not have input box. 4282 // Small pods do not have input box.
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
4426 event, this.listeners_[event][0], this.listeners_[event][1]); 4408 event, this.listeners_[event][0], this.listeners_[event][1]);
4427 } 4409 }
4428 $('login-header-bar').buttonsTabIndex = UserPodTabOrder.HEADER_BAR; 4410 $('login-header-bar').buttonsTabIndex = UserPodTabOrder.HEADER_BAR;
4429 4411
4430 if (this.podPlacementPostponed_) { 4412 if (this.podPlacementPostponed_) {
4431 this.podPlacementPostponed_ = false; 4413 this.podPlacementPostponed_ = false;
4432 this.placePods_(); 4414 this.placePods_();
4433 this.maybePreselectPod(); 4415 this.maybePreselectPod();
4434 } 4416 }
4435 4417
4436 this.updatePodNameArea(); 4418 this.updatePodNameArea_();
4437 }, 4419 },
4438 4420
4439 /** 4421 /**
4440 * Called when the element is hidden. 4422 * Called when the element is hidden.
4441 */ 4423 */
4442 handleHide: function() { 4424 handleHide: function() {
4443 for (var event in this.listeners_) { 4425 for (var event in this.listeners_) {
4444 this.ownerDocument.removeEventListener( 4426 this.ownerDocument.removeEventListener(
4445 event, this.listeners_[event][0], this.listeners_[event][1]); 4427 event, this.listeners_[event][0], this.listeners_[event][1]);
4446 } 4428 }
(...skipping 27 matching lines...) Expand all
4474 if (pod && pod.multiProfilesPolicyApplied) { 4456 if (pod && pod.multiProfilesPolicyApplied) {
4475 pod.userTypeBubbleElement.classList.remove('bubble-shown'); 4457 pod.userTypeBubbleElement.classList.remove('bubble-shown');
4476 } 4458 }
4477 } 4459 }
4478 }; 4460 };
4479 4461
4480 return { 4462 return {
4481 PodRow: PodRow 4463 PodRow: PodRow
4482 }; 4464 };
4483 }); 4465 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698