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

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: Adjust animation duration and add small screen handling 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 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
1214 1178
1215 /** 1179 /**
1216 * Gets the pod style. 1180 * Gets the pod style.
1217 * @return {UserPod.Style} Pod style. 1181 * @return {UserPod.Style} Pod style.
1218 */ 1182 */
1219 getPodStyle: function() { 1183 getPodStyle: function() {
1220 if (this.querySelector('.small-pod').hidden) 1184 if (this.querySelector('.small-pod').hidden)
1221 return UserPod.Style.LARGE; 1185 return UserPod.Style.LARGE;
1222 if (this.querySelector('.small-pod').classList.contains('extra-small')) 1186 if (this.querySelector('.small-pod').classList.contains('extra-small'))
1223 return UserPod.Style.EXTRA_SMALL; 1187 return UserPod.Style.EXTRA_SMALL;
1224 return UserPod.Style.SMALL; 1188 return UserPod.Style.SMALL;
1225 }, 1189 },
1226 1190
1227 /** 1191 /**
1228 * Updates the user pod element. 1192 * Updates the user pod element.
1229 */ 1193 */
1230 update: function() { 1194 update: function() {
1231 var imageSrc = 'chrome://userimage/' + this.user.username + 1195 var imageSrc = 'chrome://userimage/' + this.user.username +
1232 '?id=' + UserPod.userImageSalt_[this.user.username]; 1196 '?id=' + UserPod.userImageSalt_[this.user.username];
1233 this.imageElement.src = imageSrc; 1197 this.imageElement.src = imageSrc;
1234 this.smallPodImageElement.src = imageSrc; 1198 this.smallPodImageElement.src = imageSrc;
(...skipping 174 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(
3613 this.screenSize.width, 3497 this.screenSize.width, 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 }
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
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 screen.style.overflowY = 'hidden';
3562 clientArea.style.position = 'absolute';
3563 clientArea.style.left = cr.ui.toCssPx(0);
3564 clientArea.style.top = cr.ui.toCssPx(0);
3565 } else {
3566 // Sets the values to default when virtual keyboard is not shown.
3567 screen.style.overflowY = 'auto';
3568 clientArea.style.position = 'relative';
3569 }
3570 },
3571
3572 /**
3664 * Called when there is one user pod. 3573 * Called when there is one user pod.
3665 * @private 3574 * @private
3666 */ 3575 */
3667 placeSinglePod_: function() { 3576 placeSinglePod_: function() {
3668 this.mainPod_.setPodStyle(UserPod.Style.LARGE); 3577 this.mainPod_.setPodStyle(UserPod.Style.LARGE);
3669 this.mainPod_.left = (this.screenSize.width - CROS_POD_WIDTH) / 2; 3578 this.mainPod_.left = (this.screenSize.width - CROS_POD_WIDTH) / 2;
3670 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2; 3579 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
3671 }, 3580 },
3672 3581
3673 /** 3582 /**
3674 * Called when there are two users pods. 3583 * Called when there are two users pods.
3675 * @private 3584 * @private
3676 */ 3585 */
3677 placePodsOnPodRow_: function() { 3586 placePodsOnPodRow_: function() {
3678 // Both pods have large size and are placed adjacently. 3587 // Both pods have large size and are placed adjacently.
3679 var secondPod = 3588 var secondPod =
3680 this.pods[0] == this.mainPod_ ? this.pods[1] : this.pods[0]; 3589 this.pods[0] == this.mainPod_ ? this.pods[1] : this.pods[0];
3681 this.mainPod_.setPodStyle(UserPod.Style.LARGE); 3590 this.mainPod_.setPodStyle(UserPod.Style.LARGE);
3682 secondPod.setPodStyle(UserPod.Style.LARGE); 3591 secondPod.setPodStyle(UserPod.Style.LARGE);
3683 3592
3684 var DOUBLE_PODS_PADDING = this.isPortraitMode() ? 32 : 118; 3593 var DOUBLE_PODS_PADDING = this.isPortraitMode_() ? 32 : 118;
3685 var leftPadding = (this.screenSize.width - (CROS_POD_WIDTH * 2 + DOUBLE_PO DS_PADDING)) / 2; 3594 var leftPadding =
3595 (this.screenSize.width - (CROS_POD_WIDTH * 2 + DOUBLE_PODS_PADDING)) /
3596 2;
3686 // Start actual positioning. 3597 // Start actual positioning.
3687 this.mainPod_.left = leftPadding; 3598 this.mainPod_.left = leftPadding;
3688 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2; 3599 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
3689 secondPod.left = leftPadding + CROS_POD_WIDTH + DOUBLE_PODS_PADDING; 3600 secondPod.left = leftPadding + CROS_POD_WIDTH + DOUBLE_PODS_PADDING;
3690 secondPod.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2; 3601 secondPod.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
3691 }, 3602 },
3692 3603
3693 /** 3604 /**
3694 * Called when there are more than two user pods. 3605 * Called when there are more than two user pods.
3695 * @private 3606 * @private
3696 */ 3607 */
3697 placePodsOnContainer_: function() { 3608 placePodsOnContainer_: function() {
3698 this.smallPodsContainer.hidden = false; 3609 this.smallPodsContainer.hidden = false;
3699 var pods = this.pods; 3610 var pods = this.pods;
3700 if ((pods.length > LANDSCAPE_MODE_LIMIT && !this.isPortraitMode()) || 3611 if ((pods.length > LANDSCAPE_MODE_LIMIT && !this.isPortraitMode_()) ||
3701 (pods.length > PORTRAIT_MODE_LIMIT && this.isPortraitMode())) { 3612 (pods.length > PORTRAIT_MODE_LIMIT && this.isPortraitMode_())) {
3702 // If the pod count exceeds limits, they should be in extra small size 3613 // If the pod count exceeds limits, they should be in extra small size
3703 // and the container will become scrollable. 3614 // and the container will become scrollable.
3704 this.placePodsOnScrollableContainer_(); 3615 this.placePodsOnScrollableContainer_();
3705 return; 3616 return;
3706 } 3617 }
3707 this.mainPod_.setPodStyle(UserPod.Style.LARGE); 3618 this.mainPod_.setPodStyle(UserPod.Style.LARGE);
3708 for (var pod of pods) { 3619 for (var pod of pods) {
3709 if (pod != this.mainPod_) { 3620 if (pod != this.mainPod_) {
3710 // All pods except the main one must be set to the small style. 3621 // All pods except the main one must be set to the small style.
3711 pod.setPodStyle(UserPod.Style.SMALL); 3622 pod.setPodStyle(UserPod.Style.SMALL);
3712 } 3623 }
3713 } 3624 }
3714 // The size of the smallPodsContainer must be updated to avoid overflow, 3625 // The size of the smallPodsContainer must be updated to avoid overflow.
3715 // otherwise unnecessary scroll bar will show up.
3716 this.smallPodsContainer.style.height = 3626 this.smallPodsContainer.style.height =
3717 cr.ui.toCssPx(this.screenSize.height); 3627 cr.ui.toCssPx(this.screenSize.height);
3718 this.smallPodsContainer.style.width = cr.ui.toCssPx(CROS_SMALL_POD_WIDTH); 3628 this.smallPodsContainer.style.width = cr.ui.toCssPx(CROS_SMALL_POD_WIDTH);
3719 3629
3720 var LEFT_PADDING = this.isPortraitMode() ? 0 : 98; 3630 var LEFT_PADDING = this.isPortraitMode_() ? 0 : 98;
3721 var MIDDLE_PADDING = this.isPortraitMode() ? 84 : 220; 3631 var MIDDLE_PADDING = this.isPortraitMode_() ? 84 : 220;
3722 var contentsWidth = LEFT_PADDING + 3632 var contentsWidth = LEFT_PADDING +
3723 CROS_POD_WIDTH + MIDDLE_PADDING + CROS_SMALL_POD_WIDTH; 3633 CROS_POD_WIDTH + MIDDLE_PADDING + CROS_SMALL_POD_WIDTH;
3724 var blankWidth = this.screenSize.width - contentsWidth; 3634 var blankWidth = this.screenSize.width - contentsWidth;
3725 var actualLeftPadding = LEFT_PADDING; 3635 var actualLeftPadding = LEFT_PADDING;
3726 actualLeftPadding += this.isPortraitMode() ? blankWidth * 2 / 3: 3636 actualLeftPadding +=
3727 blankWidth / 2; 3637 this.isPortraitMode_() ? blankWidth * 2 / 3 : blankWidth / 2;
3728 var SMALL_POD_PADDING = 54; 3638 var SMALL_POD_PADDING = 54;
3729 var actualSmallPodPadding = SMALL_POD_PADDING; 3639 var actualSmallPodPadding = SMALL_POD_PADDING;
3730 var smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT + 3640 var smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT +
3731 (pods.length - 2) * actualSmallPodPadding; 3641 (pods.length - 2) * actualSmallPodPadding;
3732 if (smallPodsTotalHeight > this.screenSize.height) { 3642
3733 // Edge case: when the virtual keyboard is present, the total height of 3643 var SCROLL_TOP_PADDING = this.isPortraitMode_() ? 66 : 72;
3734 // the smallPodsContainer may exceed the screen height. Decrease the 3644 if (smallPodsTotalHeight + SCROLL_TOP_PADDING * 2 >
3735 // padding among small pods according to the design spec. 3645 this.screenSize.height) {
3736 actualSmallPodPadding = 32; 3646 // Edge case: the design spec assumes that the screen height is large
3737 smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT + 3647 // enough if the pod count limits set above are not exceeded, but for
3738 (pods.length - 2) * actualSmallPodPadding; 3648 // smaller screens the contents may still overflow.
3649 // SCROLL_TOP_PADDING denotes the smallest top padding we can tolerate
3650 // before allowing the container to overflow and show the scroll bar.
3651 // If virtual keyboard is shown, we will first try a smaller padding
3652 // and recalculate the total height.
3653 if (this.isScreenShrinked_()) {
3654 actualSmallPodPadding = 32;
3655 smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT +
3656 (pods.length - 2) * actualSmallPodPadding;
3657 }
3658 // If virtual keyboard is not shown, or the updated total height still
3659 // exceeds screen height, fall to the scrollable container case.
3660 if (smallPodsTotalHeight + SCROLL_TOP_PADDING * 2 >
3661 this.screenSize.height) {
3662 this.placePodsOnScrollableContainer_();
3663 return;
3664 }
3739 } 3665 }
3740 3666
3741 // Start positioning of the main pod and the smallPodsContainer. 3667 // Start positioning of the main pod and the smallPodsContainer.
3742 this.mainPod_.left = actualLeftPadding; 3668 this.mainPod_.left = actualLeftPadding;
3743 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2; 3669 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
3744 this.smallPodsContainer.style.left = 3670 this.smallPodsContainer.style.left =
3745 cr.ui.toCssPx(actualLeftPadding + CROS_POD_WIDTH + MIDDLE_PADDING); 3671 cr.ui.toCssPx(actualLeftPadding + CROS_POD_WIDTH + MIDDLE_PADDING);
3746 this.smallPodsContainer.style.top = cr.ui.toCssPx(0); 3672 this.smallPodsContainer.style.top = cr.ui.toCssPx(0);
3747 // Start positioning of the small pods inside the smallPodsContainer. 3673 // Start positioning of the small pods inside the smallPodsContainer.
3748 var smallPodsTopPadding = (this.screenSize.height - smallPodsTotalHeight) / 2; 3674 var smallPodsTopPadding =
3675 (this.screenSize.height - smallPodsTotalHeight) / 2;
3749 for (var pod of pods) { 3676 for (var pod of pods) {
3750 if (pod == this.mainPod_) { 3677 if (pod == this.mainPod_) {
3751 continue; 3678 continue;
3752 } 3679 }
3753 pod.left = 0; 3680 pod.left = 0;
3754 pod.top = smallPodsTopPadding; 3681 pod.top = smallPodsTopPadding;
3755 smallPodsTopPadding += CROS_SMALL_POD_HEIGHT + actualSmallPodPadding; 3682 smallPodsTopPadding += CROS_SMALL_POD_HEIGHT + actualSmallPodPadding;
3756 } 3683 }
3757 }, 3684 },
3758 3685
3759 /** 3686 /**
3760 * Called when there are more than 6 user pods in landscape mode, or more 3687 * Called when there are more than 6 user pods in landscape mode, or more
3761 * than 10 user pods in portrait mode. 3688 * than 10 user pods in portrait mode.
3762 * @private 3689 * @private
3763 */ 3690 */
3764 placePodsOnScrollableContainer_: function() { 3691 placePodsOnScrollableContainer_: function() {
3765 this.smallPodsContainer.hidden = false; 3692 this.smallPodsContainer.hidden = false;
3766 // Add a dark overlay. 3693 // Add a dark overlay.
3767 this.smallPodsContainer.classList.add('scroll'); 3694 this.smallPodsContainer.classList.add('scroll');
3768 var pods = this.pods; 3695 var pods = this.pods;
3769 this.mainPod_.setPodStyle(UserPod.Style.LARGE); 3696 this.mainPod_.setPodStyle(UserPod.Style.LARGE);
3770 for (var pod of pods) { 3697 for (var pod of pods) {
3771 if (pod != this.mainPod_) { 3698 if (pod != this.mainPod_) {
3772 // All pods except the main one must be set to the extra small style. 3699 // All pods except the main one must be set to the extra small style.
3773 pod.setPodStyle(UserPod.Style.EXTRA_SMALL); 3700 pod.setPodStyle(UserPod.Style.EXTRA_SMALL);
3774 } 3701 }
3775 } 3702 }
3776 3703
3777 var SCROLL_LEFT_PADDING = this.isPortraitMode() ? 46 : 72; 3704 var SCROLL_LEFT_PADDING = this.isPortraitMode_() ? 46 : 72;
3778 var SCROLL_RIGHT_PADDING = this.isPortraitMode() ? 12 : 72; 3705 var SCROLL_RIGHT_PADDING = this.isPortraitMode_() ? 12 : 72;
3779 // The offsetWidth of the smallPodsContainer. 3706 // The offsetWidth of the smallPodsContainer.
3780 var scrollAreaWidth = SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH + 3707 var scrollAreaWidth = SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH +
3781 SCROLL_RIGHT_PADDING; 3708 SCROLL_RIGHT_PADDING;
3782 var mainPodPadding = (this.screenSize.width - 3709 var mainPodPadding = (this.screenSize.width -
3783 scrollAreaWidth - CROS_POD_WIDTH) / 2; 3710 scrollAreaWidth - CROS_POD_WIDTH) / 2;
3784 var SCROLL_TOP_PADDING = this.isPortraitMode() ? 66 : 72; 3711 var SCROLL_TOP_PADDING = this.isPortraitMode_() ? 66 : 72;
3785 var EXTRA_SMALL_POD_PADDING = 32; 3712 var EXTRA_SMALL_POD_PADDING = 32;
3786 // Start positioning of the main pod and the smallPodsContainer. 3713 // Start positioning of the main pod and the smallPodsContainer.
3787 this.mainPod_.left = mainPodPadding; 3714 this.mainPod_.left = mainPodPadding;
3788 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2; 3715 this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
3789 this.smallPodsContainer.style.left = 3716 this.smallPodsContainer.style.left =
3790 cr.ui.toCssPx(mainPodPadding * 2 + CROS_POD_WIDTH); 3717 cr.ui.toCssPx(mainPodPadding * 2 + CROS_POD_WIDTH);
3791 this.smallPodsContainer.style.top = cr.ui.toCssPx(0); 3718 this.smallPodsContainer.style.top = cr.ui.toCssPx(0);
3792 3719
3793 // Precalculate the total height of the scrollable container and check if 3720 // Precalculate the total height of the scrollable container and check if
3794 // it indeed exceeds the screen height. 3721 // it indeed exceeds the screen height.
3795 var scrollHeight = 0; 3722 var scrollHeight = 0;
3796 for (var pod of pods) { 3723 for (var pod of pods) {
3797 if (pod == this.mainPod_) { 3724 if (pod == this.mainPod_) {
3798 continue; 3725 continue;
3799 } 3726 }
3800 scrollHeight += CROS_EXTRA_SMALL_POD_HEIGHT + EXTRA_SMALL_POD_PADDING; 3727 scrollHeight += CROS_EXTRA_SMALL_POD_HEIGHT + EXTRA_SMALL_POD_PADDING;
3801 } 3728 }
3802 scrollHeight -= EXTRA_SMALL_POD_PADDING; 3729 scrollHeight -= EXTRA_SMALL_POD_PADDING;
3803 // The smallPodsContainer should occupy the full screen vertically. 3730 // The smallPodsContainer should occupy the full screen vertically.
3804 this.smallPodsContainer.style.height = cr.ui.toCssPx(this.screenSize.heigh t); 3731 this.smallPodsContainer.style.height =
3732 cr.ui.toCssPx(this.screenSize.height);
3805 this.smallPodsContainer.style.width = cr.ui.toCssPx( 3733 this.smallPodsContainer.style.width = cr.ui.toCssPx(
3806 SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH + 3734 SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH +
3807 SCROLL_RIGHT_PADDING); 3735 SCROLL_RIGHT_PADDING);
3808 3736
3809 // SCROLL_TOP_PADDING denotes the smallest top padding we can tolerate 3737 // SCROLL_TOP_PADDING denotes the smallest top padding we can tolerate
3810 // before allowing the container to overflow and show the scroll bar. 3738 // before allowing the container to overflow and show the scroll bar.
3811 var actualTopPadding = SCROLL_TOP_PADDING; 3739 var actualTopPadding = SCROLL_TOP_PADDING;
3812 if ((this.screenSize.height - scrollHeight) / 2 > actualTopPadding) { 3740 if ((this.screenSize.height - scrollHeight) / 2 > actualTopPadding) {
3813 // Edge case: the total height of the scrollable container does not 3741 // Edge case: the total height of the scrollable container does not
3814 // exceed the screen height (minus the neceesary padding), so the 3742 // exceed the screen height (minus the neceesary padding), so the
3815 // scroll bar will not appear. 3743 // scroll bar will not appear.
3816 // In this case, we still want to keep the extra small pod size and 3744 // 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 3745 // the overlay, but the top and bottom padding should be adjusted
3818 // to ensure a symmetric layout. 3746 // to ensure a symmetric layout.
3819 actualTopPadding = (this.screenSize.height - scrollHeight) / 2; 3747 actualTopPadding = (this.screenSize.height - scrollHeight) / 2;
3820 } else if (!Oobe.getInstance().virtualKeyboardShown) { 3748 } else if (!this.isScreenShrinked_()) {
3821 // The scroll bar will definitely be shown if we reach here. A gradient 3749 // 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 3750 // 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 3751 // 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. 3752 // to add the mask and the original top padding value should be kept.
3825 actualTopPadding = SCROLL_MASK_HEIGHT; 3753 actualTopPadding = SCROLL_MASK_HEIGHT;
3826 this.showScrollMask(); 3754 this.showScrollMask_();
3827 } 3755 }
3828 3756
3829 // Start positioning of the small pods inside the smallPodsContainer. 3757 // Start positioning of the small pods inside the smallPodsContainer.
3830 var topPadding = actualTopPadding; 3758 var topPadding = actualTopPadding;
3831 var lastPod = undefined; 3759 var lastPod = undefined;
3832 for (var pod of pods) { 3760 for (var pod of pods) {
3833 if (pod == this.mainPod_) { 3761 if (pod == this.mainPod_) {
3834 continue; 3762 continue;
3835 } 3763 }
3836 pod.left = SCROLL_LEFT_PADDING; 3764 pod.left = SCROLL_LEFT_PADDING;
(...skipping 18 matching lines...) Expand all
3855 document.querySelector('.small-pod-container-mask').hidden = true; 3783 document.querySelector('.small-pod-container-mask').hidden = true;
3856 document.querySelector('.small-pod-container-mask.rotate').hidden = true; 3784 document.querySelector('.small-pod-container-mask.rotate').hidden = true;
3857 this.smallPodsContainer.classList.remove('scroll'); 3785 this.smallPodsContainer.classList.remove('scroll');
3858 var pods = this.pods; 3786 var pods = this.pods;
3859 for (var pod of pods) { 3787 for (var pod of pods) {
3860 // There is a chance that one of the pods has a bottom padding, so 3788 // 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 3789 // 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 3790 // the last position in the scrollable container, a bottom padding
3863 // was added to ensure a symmetric layout. 3791 // was added to ensure a symmetric layout.
3864 pod.style.paddingBottom = cr.ui.toCssPx(0); 3792 pod.style.paddingBottom = cr.ui.toCssPx(0);
3793 // Remove the switch animation that might be added earlier.
3794 pod.imageElement.classList.remove('switch-image-animation');
3795 pod.smallPodImageElement.classList.remove('switch-image-animation');
3865 } 3796 }
3866 }, 3797 },
3867 3798
3868 /** 3799 /**
3869 * Check if the screen is in portrait mode. 3800 * Checks if the screen is in portrait mode.
3870 * @return {boolean} True if in portrait mode. 3801 * @return {boolean} True if in portrait mode.
3871 */ 3802 */
3872 isPortraitMode: function() { 3803 isPortraitMode_: function() {
3873 return this.screenSize.width < 3804 return this.screenSize.width < this.screenSize.height;
3874 this.screenSize.height; 3805 },
3806
3807 /**
3808 * Checks if the screen is shrinked, i.e., when showing virtual keyboard.
3809 * We used to check Oobe.getInstance().virtualKeyboardShown directly
3810 * but there were occasional bugs because that value may not be updated yet
3811 * during pod placement.
3812 * @return {boolean} True if the screen is shrinked.
3813 */
3814 isScreenShrinked_: function() {
3815 return this.screenSize.height <= Oobe.getInstance().clientAreaSize.height;
3875 }, 3816 },
3876 3817
3877 /** 3818 /**
3878 * Called when scroll bar is shown and we need a mask for the header bar. 3819 * Called when scroll bar is shown and we need a mask for the header bar.
3879 * @private 3820 * @private
3880 */ 3821 */
3881 showScrollMask: function() { 3822 showScrollMask_: function() {
3882 var topMask = document.querySelector('.small-pod-container-mask'); 3823 var topMask = document.querySelector('.small-pod-container-mask');
3883 topMask.hidden = false; 3824 topMask.hidden = false;
3884 topMask.style.left = this.smallPodsContainer.style.left; 3825 topMask.style.left = this.smallPodsContainer.style.left;
3885 topMask.style.width = this.smallPodsContainer.style.width; 3826 topMask.style.width = this.smallPodsContainer.style.width;
3886 // The bottom mask is a rotation of the top mask. 3827 // The bottom mask is a rotation of the top mask.
3887 var bottomMask = 3828 var bottomMask =
3888 document.querySelector('.small-pod-container-mask.rotate'); 3829 document.querySelector('.small-pod-container-mask.rotate');
3889 bottomMask.hidden = false; 3830 bottomMask.hidden = false;
3890 bottomMask.style.left = this.smallPodsContainer.style.left; 3831 bottomMask.style.left = this.smallPodsContainer.style.left;
3891 bottomMask.style.width = this.smallPodsContainer.style.width; 3832 bottomMask.style.width = this.smallPodsContainer.style.width;
3892 // The bottom mask should overlap with the header bar, and its z-index 3833 // 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. 3834 // is chosen to ensure it does not block users from using the header bar.
3894 bottomMask.style.top = cr.ui.toCssPx( 3835 bottomMask.style.top =
3895 this.screenSize.height - 3836 cr.ui.toCssPx(this.screenSize.height - SCROLL_MASK_HEIGHT);
3896 SCROLL_MASK_HEIGHT);
3897 }, 3837 },
3898 3838
3899 /** 3839 /**
3900 * Makes sure that user name on each large pod is centered and extra long 3840 * Makes sure that:
3901 * name does not exceed max width. Names on small pods do not need to be 3841 * 1) User name on each large pod is centered.
3902 * dynamically updated. 3842 * 2) Extra long names don't exceed maximum pod width.
3843 * 3) Action box menus are either left-aligned or right-aligned with
3844 * the drop down button.
3903 * @private 3845 * @private
3904 */ 3846 */
3905 updatePodNameArea: function() { 3847 updatePodNameArea_: function() {
3906 this.querySelectorAll('.name-container').forEach(function(nameArea) { 3848 var pods = this.pods;
3907 var nameElement = nameArea.querySelector('.name'); 3849 for (var pod of pods) {
3908 var leftMargin = (CROS_POD_WIDTH - nameElement.offsetWidth) / 2; 3850 if (pods.length > POD_ROW_LIMIT && pod != this.mainPod_)
3851 continue;
3852 var nameArea = pod.querySelector('.name-container');
3853 var leftMargin = (CROS_POD_WIDTH - pod.nameElement.offsetWidth) / 2;
3909 if (leftMargin > 0) 3854 if (leftMargin > 0)
3910 nameArea.style.left = cr.ui.toCssPx(leftMargin); 3855 nameArea.style.left = cr.ui.toCssPx(leftMargin);
3911 else 3856 else {
3912 nameElement.style.width = cr.ui.toCssPx(CROS_POD_WIDTH); 3857 pod.nameElement.style.width = cr.ui.toCssPx(CROS_POD_WIDTH);
3913 }); 3858 nameArea.style.left = cr.ui.toCssPx(0);
3859 }
3860 // Update action box menu position to ensure it doesn't overlap with
3861 // elements outside the pod.
3862 var actionBoxMenu = pod.querySelector('.action-box-menu');
3863 var actionBoxButton = pod.querySelector('.action-box-button');
3864 var MENU_TOP_PADDING = 7;
3865 actionBoxMenu.style.top =
3866 cr.ui.toCssPx(actionBoxButton.offsetHeight + MENU_TOP_PADDING);
3867 if (this.isPortraitMode_() && pods.length > 1) {
3868 // Confine the menu inside the pod when it may overlap with outside
3869 // elements.
3870 actionBoxMenu.style.left = 'auto';
3871 actionBoxMenu.style.right = cr.ui.toCssPx(0);
3872 } else {
3873 actionBoxMenu.style.left = cr.ui.toCssPx(
3874 pod.nameElement.offsetWidth + actionBoxButton.style.marginLeft);
3875 actionBoxMenu.style.right = 'auto';
3876 }
3877 // Add ripple animation.
3878 var actionBoxRippleEffect =
3879 pod.querySelector('.action-box-button.ripple-circle');
3880 actionBoxRippleEffect.style.left = actionBoxMenu.style.left;
3881 actionBoxRippleEffect.style.top =
3882 cr.ui.toCssPx(actionBoxButton.style.marginTop);
3883 }
3914 }, 3884 },
3915 3885
3916 /** 3886 /**
3917 * Called when a small or extra small pod is clicked to trigger the switch 3887 * Called when a small or extra small pod is clicked to trigger the switch
3918 * with the main pod. 3888 * with the main pod.
3919 */ 3889 */
3920 switchMainPod: function(pod) { 3890 switchMainPod: function(pod) {
3921 if (this.disabled) { 3891 if (this.disabled) {
3922 console.error('Cannot change main pod while sign-in UI is disabled.'); 3892 console.error('Cannot change main pod while sign-in UI is disabled.');
3923 return; 3893 return;
3924 } 3894 }
3925 if (!this.mainPod_) { 3895 if (!this.mainPod_) {
3926 console.error('Attempt to switch a non-existing main pod.'); 3896 console.error('Attempt to switch a non-existing main pod.');
3927 return; 3897 return;
3928 } 3898 }
3929 // Find the index of the small pod. 3899 // Find the index of the small pod.
3930 var insert = 0; 3900 var insert = 0;
3931 var children = pod.parentNode.children; 3901 var children = pod.parentNode.children;
3932 while (insert < children.length && children[insert] != pod) 3902 while (insert < children.length && children[insert] != pod)
3933 insert++; 3903 insert++;
3934 if (insert >= children.length) { 3904 if (insert >= children.length) {
3935 console.error('Attempt to switch a non-existing small pod.'); 3905 console.error('Attempt to switch a non-existing small pod.');
3936 return; 3906 return;
3937 } 3907 }
3938 // Switch style of the two pods. 3908 // Switch style of the two pods.
3939 this.mainPod_.setPodStyle(pod.getPodStyle()); 3909 this.mainPod_.setPodStyle(pod.getPodStyle());
3940 pod.setPodStyle(UserPod.Style.LARGE); 3910 pod.setPodStyle(UserPod.Style.LARGE);
3911 // Add switch animation.
3912 this.mainPod_.smallPodImageElement.classList.add(
3913 'switch-image-animation');
3914 pod.imageElement.classList.add('switch-image-animation');
3941 3915
3942 // Switch parent and position of the two pods. 3916 // Switch parent and position of the two pods.
3943 var left = pod.left; 3917 var left = pod.left;
3944 var top = pod.top; 3918 var top = pod.top;
3945 // Edge case: paddingBottom should be switched too because there's a 3919 // 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 3920 // chance that the small pod was at the end of the scrollable container
3947 // and had a non-zero paddingBottom. 3921 // and had a non-zero paddingBottom.
3948 var paddingBottom = pod.style.paddingBottom; 3922 var paddingBottom = pod.style.paddingBottom;
3949 var parent = pod.parentNode; 3923 var parent = pod.parentNode;
3950 parent.removeChild(pod); 3924 parent.removeChild(pod);
3951 this.appendChild(pod); 3925 this.appendChild(pod);
3952 pod.left = this.mainPod_.left; 3926 pod.left = this.mainPod_.left;
3953 pod.top = this.mainPod_.top; 3927 pod.top = this.mainPod_.top;
3954 pod.style.paddingBottom = cr.ui.toCssPx(0); 3928 pod.style.paddingBottom = cr.ui.toCssPx(0);
3955 3929
3956 this.removeChild(this.mainPod_); 3930 this.removeChild(this.mainPod_);
3957 // It must have the same index with the original small pod, instead 3931 // 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' 3932 // of being appended as the last child, in order to maintain the 'Tab'
3959 // order. 3933 // order.
3960 parent.insertBefore(this.mainPod_, children[insert]); 3934 parent.insertBefore(this.mainPod_, children[insert]);
3961 this.mainPod_.left = left; 3935 this.mainPod_.left = left;
3962 this.mainPod_.top = top; 3936 this.mainPod_.top = top;
3963 this.mainPod_.style.paddingBottom = paddingBottom; 3937 this.mainPod_.style.paddingBottom = paddingBottom;
3964 this.mainPod_ = pod; 3938 this.mainPod_ = pod;
3965 // Focus the new main pod. 3939 // The new main pod should already be focused but we need a focus update
3966 this.focusPod(this.mainPod_); 3940 // in order to focus on the input box.
3967 this.updatePodNameArea(); 3941 this.focusPod(this.mainPod_, true /* force */);
3942 this.updatePodNameArea_();
3968 }, 3943 },
3969 3944
3970 /** 3945 /**
3971 * Returns dimensions of screen including the header bar. 3946 * Returns dimensions of screen including the header bar.
3972 * @type {Object} 3947 * @type {Object}
3973 */ 3948 */
3974 get screenSize() { 3949 get screenSize() {
3975 var container = $('scroll-container'); 3950 var container = $('scroll-container');
3976 return {width: container.offsetWidth, height: container.offsetHeight}; 3951 return {width: container.offsetWidth, height: container.offsetHeight};
3977 }, 3952 },
3978 3953
3979 /** 3954 /**
3980 * Number of columns. 3955 * Displays a banner containing |message|. If the banner is already present
3981 * @type {?number} 3956 * this function updates the message in the banner.
3957 * @param {string} message Text to be displayed or empty to hide the banner.
3982 */ 3958 */
3983 set columns(columns) { 3959 showBannerMessage: function(message) {
3984 // Cannot use 'columns' here. 3960 var banner = $('signin-banner');
3985 this.setAttribute('ncolumns', columns); 3961 banner.textContent = message;
3986 }, 3962 banner.classList.toggle('message-set', !!message);
3987 get columns() { 3963 var bannerContainer = $('signin-banner-container1');
3988 return parseInt(this.getAttribute('ncolumns')); 3964 var BANNER_TOP_PADDING = this.isScreenShrinked_() ? 0 : 38;
3965 bannerContainer.style.top = cr.ui.toCssPx(
3966 this.mainPod_.top + CROS_POD_HEIGHT + BANNER_TOP_PADDING);
3967 if (this.pods.length <= POD_ROW_LIMIT)
3968 bannerContainer.style.left =
3969 cr.ui.toCssPx((this.screenSize.width - BANNER_MESSAGE_WIDTH) / 2);
3970 else {
3971 var leftPadding =
3972 this.mainPod_.left - (BANNER_MESSAGE_WIDTH - CROS_POD_WIDTH) / 2;
3973 bannerContainer.style.left = cr.ui.toCssPx(Math.max(leftPadding, 0));
3974 }
3989 }, 3975 },
3990 3976
3991 /** 3977 /**
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. 3978 * Whether the pod is currently focused.
4005 * @param {UserPod} pod Pod to check for focus. 3979 * @param {UserPod} pod Pod to check for focus.
4006 * @return {boolean} Pod focus status. 3980 * @return {boolean} Pod focus status.
4007 */ 3981 */
4008 isFocused: function(pod) { 3982 isFocused: function(pod) {
4009 return this.focusedPod_ == pod; 3983 return this.focusedPod_ == pod;
4010 }, 3984 },
4011 3985
4012 /** 3986 /**
4013 * Focuses a given user pod or clear focus when given null. 3987 * 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| 4046 // |opt_skipInputFocus| is true. When |multiProfilesPolicyApplied|
4073 // is false, it doesn't focus on the password input box by default. 4047 // is false, it doesn't focus on the password input box by default.
4074 podToFocus.focus(); 4048 podToFocus.focus();
4075 } 4049 }
4076 4050
4077 // focusPod() automatically loads wallpaper 4051 // focusPod() automatically loads wallpaper
4078 if (!podToFocus.user.isApp) 4052 if (!podToFocus.user.isApp)
4079 chrome.send('focusPod', [podToFocus.user.username]); 4053 chrome.send('focusPod', [podToFocus.user.username]);
4080 this.firstShown_ = false; 4054 this.firstShown_ = false;
4081 this.lastFocusedPod_ = podToFocus; 4055 this.lastFocusedPod_ = podToFocus;
4082 this.scrollFocusedPodIntoView();
4083 this.setUserPodFingerprintIcon( 4056 this.setUserPodFingerprintIcon(
4084 podToFocus.user.username, FINGERPRINT_STATES.DEFAULT); 4057 podToFocus.user.username, FINGERPRINT_STATES.DEFAULT);
4085 } else { 4058 } else {
4086 chrome.send('noPodFocused'); 4059 chrome.send('noPodFocused');
4087 } 4060 }
4088 this.insideFocusPod_ = false; 4061 this.insideFocusPod_ = false;
4089 }, 4062 },
4090 4063
4091 /** 4064 /**
4092 * Resets wallpaper to the last active user's wallpaper, if any. 4065 * Resets wallpaper to the last active user's wallpaper, if any.
(...skipping 14 matching lines...) Expand all
4107 /** 4080 /**
4108 * Sets currently activated pod. 4081 * Sets currently activated pod.
4109 * @param {UserPod} pod Pod to check for focus. 4082 * @param {UserPod} pod Pod to check for focus.
4110 * @param {Event} e Event object. 4083 * @param {Event} e Event object.
4111 */ 4084 */
4112 setActivatedPod: function(pod, e) { 4085 setActivatedPod: function(pod, e) {
4113 if (this.disabled) { 4086 if (this.disabled) {
4114 console.error('Cannot activate pod while sign-in UI is disabled.'); 4087 console.error('Cannot activate pod while sign-in UI is disabled.');
4115 return; 4088 return;
4116 } 4089 }
4090 // If testing mode is enabled and a positive integer was entered, abort
4091 // the activation process and start testing mode.
4092 if (pod && this.testingModeEnabled_) {
4093 var userCount = pod.passwordElement.value;
4094 if (parseInt(userCount) == userCount && userCount > 0) {
4095 this.showDummyUsersForTesting(userCount);
4096 return;
4097 }
4098 }
4117 if (pod && pod.activate(e)) 4099 if (pod && pod.activate(e))
4118 this.activatedPod_ = pod; 4100 this.activatedPod_ = pod;
4119 }, 4101 },
4120 4102
4121 /** 4103 /**
4104 * Used for testing only. Create the specified number of dummy users and
4105 * conveniently test the behaviors under different number of pods.
4106 * @param {number} count The number of users we want to test for.
4107 */
4108 showDummyUsersForTesting: function(count) {
4109 if (!this.testingModeEnabled_) {
4110 console.error(
4111 'Attempt to create dummy users when testing mode is disabled.');
4112 return;
4113 }
4114 var pods = this.pods;
4115 for (var pod of pods)
4116 pod.parentNode.removeChild(pod);
4117 var sampleUser = this.users_[0];
4118 var users = [];
4119 for (var i = 0; i < count; i++)
4120 users.push(sampleUser);
4121
4122 this.loadPods(users);
4123 },
4124
4125 /**
4122 * The pod of the signed-in user, if any; null otherwise. 4126 * The pod of the signed-in user, if any; null otherwise.
4123 * @type {?UserPod} 4127 * @type {?UserPod}
4124 */ 4128 */
4125 get lockedPod() { 4129 get lockedPod() {
4126 for (var i = 0, pod; pod = this.pods[i]; ++i) { 4130 for (var i = 0, pod; pod = this.pods[i]; ++i) {
4127 if (pod.user.signedIn) 4131 if (pod.user.signedIn)
4128 return pod; 4132 return pod;
4129 } 4133 }
4130 return null; 4134 return null;
4131 }, 4135 },
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
4228 for (var i = 0, pod; pod = this.pods[i]; ++i) 4232 for (var i = 0, pod; pod = this.pods[i]; ++i)
4229 pod.isActionBoxMenuActive = false; 4233 pod.isActionBoxMenuActive = false;
4230 } 4234 }
4231 4235
4232 // Clears focus if not clicked on a pod and if there's more than one pod. 4236 // Clears focus if not clicked on a pod and if there's more than one pod.
4233 var pod = findAncestorByClass(e.target, 'pod'); 4237 var pod = findAncestorByClass(e.target, 'pod');
4234 if ((!pod || pod.parentNode != this) && !this.alwaysFocusSinglePod) { 4238 if ((!pod || pod.parentNode != this) && !this.alwaysFocusSinglePod) {
4235 this.focusPod(); 4239 this.focusPod();
4236 } 4240 }
4237 4241
4238 if (pod) 4242 if (pod && pod.getPodStyle() == UserPod.Style.LARGE)
4239 pod.isActionBoxMenuHovered = true; 4243 pod.isActionBoxMenuHovered = true;
4240 4244
4241 // Return focus back to single pod. 4245 // Return focus back to single pod.
4242 if (this.alwaysFocusSinglePod && !pod) { 4246 if (this.alwaysFocusSinglePod && !pod) {
4243 if ($('login-header-bar').contains(e.target)) 4247 if ($('login-header-bar').contains(e.target))
4244 return; 4248 return;
4245 this.focusPod(this.focusedPod_, true /* force */); 4249 // If the click is outside the single pod, still focus on that pod
4250 // but do not focus on input box any more. This makes virtual keyboard
4251 // (if present) disappear.
4252 this.focusPod(
4253 this.focusedPod_, true /* force */, true /* opt_skipInputFocus */);
4246 this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown'); 4254 this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown');
4247 this.focusedPod_.isActionBoxMenuHovered = false; 4255 this.focusedPod_.isActionBoxMenuHovered = false;
4248 } 4256 }
4249 }, 4257 },
4250 4258
4251 /** 4259 /**
4252 * Handler of mouse move event. 4260 * Handler of mouse move event.
4253 * @param {Event} e Click Event object. 4261 * @param {Event} e Click Event object.
4254 * @private 4262 * @private
4255 */ 4263 */
(...skipping 23 matching lines...) Expand all
4279 4287
4280 /** 4288 /**
4281 * Handles focus event. 4289 * Handles focus event.
4282 * @param {Event} e Focus Event object. 4290 * @param {Event} e Focus Event object.
4283 * @private 4291 * @private
4284 */ 4292 */
4285 handleFocus_: function(e) { 4293 handleFocus_: function(e) {
4286 if (this.disabled) 4294 if (this.disabled)
4287 return; 4295 return;
4288 if (e.target.parentNode == this) { 4296 if (e.target.parentNode == this) {
4289 // Focus on a pod 4297 // Handles focus event on a large pod.
4290 if (e.target.classList.contains('focused')) { 4298 if (e.target.classList.contains('focused')) {
4299 // Edge case: prevent input box from receiving unncessary focus
4300 // (thus hiding virtual keyboard) when remove user is clicked.
4301 if (e.target.isActionBoxMenuActive)
4302 return;
4291 if (!e.target.multiProfilesPolicyApplied) 4303 if (!e.target.multiProfilesPolicyApplied)
4292 e.target.focusInput(); 4304 e.target.focusInput();
4293 else 4305 else
4294 e.target.userTypeBubbleElement.classList.add('bubble-shown'); 4306 e.target.userTypeBubbleElement.classList.add('bubble-shown');
4295 } else 4307 } else
4296 this.focusPod(e.target); 4308 this.focusPod(e.target);
4297 return; 4309 return;
4298 } 4310 }
4299 4311
4300 // Small pods do not have input box. 4312 // 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]); 4438 event, this.listeners_[event][0], this.listeners_[event][1]);
4427 } 4439 }
4428 $('login-header-bar').buttonsTabIndex = UserPodTabOrder.HEADER_BAR; 4440 $('login-header-bar').buttonsTabIndex = UserPodTabOrder.HEADER_BAR;
4429 4441
4430 if (this.podPlacementPostponed_) { 4442 if (this.podPlacementPostponed_) {
4431 this.podPlacementPostponed_ = false; 4443 this.podPlacementPostponed_ = false;
4432 this.placePods_(); 4444 this.placePods_();
4433 this.maybePreselectPod(); 4445 this.maybePreselectPod();
4434 } 4446 }
4435 4447
4436 this.updatePodNameArea(); 4448 this.updatePodNameArea_();
4437 }, 4449 },
4438 4450
4439 /** 4451 /**
4440 * Called when the element is hidden. 4452 * Called when the element is hidden.
4441 */ 4453 */
4442 handleHide: function() { 4454 handleHide: function() {
4443 for (var event in this.listeners_) { 4455 for (var event in this.listeners_) {
4444 this.ownerDocument.removeEventListener( 4456 this.ownerDocument.removeEventListener(
4445 event, this.listeners_[event][0], this.listeners_[event][1]); 4457 event, this.listeners_[event][0], this.listeners_[event][1]);
4446 } 4458 }
(...skipping 27 matching lines...) Expand all
4474 if (pod && pod.multiProfilesPolicyApplied) { 4486 if (pod && pod.multiProfilesPolicyApplied) {
4475 pod.userTypeBubbleElement.classList.remove('bubble-shown'); 4487 pod.userTypeBubbleElement.classList.remove('bubble-shown');
4476 } 4488 }
4477 } 4489 }
4478 }; 4490 };
4479 4491
4480 return { 4492 return {
4481 PodRow: PodRow 4493 PodRow: PodRow
4482 }; 4494 };
4483 }); 4495 });
OLDNEW
« no previous file with comments | « ui/login/account_picker/md_user_pod_row.css ('k') | ui/login/account_picker/md_user_pod_template.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698