Chromium Code Reviews| Index: ui/login/account_picker/md_user_pod_row.js |
| diff --git a/ui/login/account_picker/md_user_pod_row.js b/ui/login/account_picker/md_user_pod_row.js |
| index e13d59bff035c8da4e0e56f043c5ef568d5febc2..20a6f42bae999fa33801e761ddb0f9afe616deea 100644 |
| --- a/ui/login/account_picker/md_user_pod_row.js |
| +++ b/ui/login/account_picker/md_user_pod_row.js |
| @@ -49,17 +49,22 @@ cr.define('login', function() { |
| * synced with computed CSS sizes of pods. |
| */ |
| var CROS_POD_WIDTH = 306; |
| + var CROS_SMALL_POD_WIDTH = 304; |
| + var CROS_EXTRA_SMALL_POD_WIDTH = 282; |
| var DESKTOP_POD_WIDTH = 180; |
| var MD_DESKTOP_POD_WIDTH = 160; |
| var PUBLIC_EXPANDED_BASIC_WIDTH = 500; |
| var PUBLIC_EXPANDED_ADVANCED_WIDTH = 610; |
| var CROS_POD_HEIGHT = 346; |
| + var CROS_SMALL_POD_HEIGHT = 74; |
| + var CROS_EXTRA_SMALL_POD_HEIGHT = 60; |
| var DESKTOP_POD_HEIGHT = 226; |
| var MD_DESKTOP_POD_HEIGHT = 200; |
| var POD_ROW_PADDING = 10; |
| var DESKTOP_ROW_PADDING = 32; |
| var CUSTOM_ICON_CONTAINER_SIZE = 40; |
| var CROS_PIN_POD_HEIGHT = 417; |
| + var SCROLL_MASK_HEIGHT = 112; |
| /** |
| * Minimal padding between user pod and virtual keyboard. |
| @@ -89,12 +94,12 @@ cr.define('login', function() { |
| * @const |
| */ |
| var UserPodTabOrder = { |
| - POD_INPUT: 1, // Password input field, Action box menu button and |
| - // the pod itself. |
| - PIN_KEYBOARD: 2, // Pin keyboard below the password input field. |
| - POD_CUSTOM_ICON: 3, // Pod custom icon next to password input field. |
| - HEADER_BAR: 4, // Buttons on the header bar (Shutdown, Add User). |
| - POD_MENU_ITEM: 5 // User pad menu items (User info, Remove user). |
| + POD_INPUT: 1, // Password input field and the pod itself. |
| + PIN_KEYBOARD: 2, // Pin keyboard below the password input field. |
| + POD_CUSTOM_ICON: 3, // Pod custom icon next to password input field. |
| + HEADER_BAR: 4, // Buttons on the header bar (Shutdown, Add User). |
| + ACTION_BOX_BUTTON: 5, // Action box menu button. |
| + POD_MENU_ITEM: 6 // User pod menu items (User info, Remove user). |
| }; |
| /** |
| @@ -155,12 +160,13 @@ cr.define('login', function() { |
| // (1) all user pods have tab index 1 so they are traversed first; |
| // (2) when a user pod is activated, its tab index is set to -1 and its |
| // main input field gets focus and tab index 1; |
| - // (3) if user pod custom icon is interactive, it has tab index 2 so it |
| - // follows the input. |
| - // (4) buttons on the header bar have tab index 3 so they follow the custom |
| - // icon, or user pod if custom icon is not interactive; |
| - // (5) Action box buttons have tab index 4 and follow header bar buttons; |
| - // (6) lastly, focus jumps to the Status Area and back to user pods. |
| + // (3) if pin keyboard is present, it has tab index 2 so it follows the input; |
| + // (4) if user pod custom icon is interactive, it has tab index 3; |
| + // (5) buttons on the header bar have tab index 4; |
| + // (6) Action box buttons have tab index 5 and follow the buttons on the |
| + // header bar; |
| + // (7) User pod menu items (if present) have tab index 6; |
| + // (8) lastly, focus jumps to the Status Area and back to user pods. |
| // |
| // 'Focus' event is handled by a capture handler for the whole document |
| // and in some cases 'mousedown' event handlers are used instead of 'click' |
| @@ -753,7 +759,7 @@ cr.define('login', function() { |
| /** @override */ |
| decorate: function() { |
| this.tabIndex = UserPodTabOrder.POD_INPUT; |
| - this.actionBoxAreaElement.tabIndex = UserPodTabOrder.POD_INPUT; |
| + this.actionBoxAreaElement.tabIndex = UserPodTabOrder.ACTION_BOX_BUTTON; |
| this.addEventListener('keydown', this.handlePodKeyDown_.bind(this)); |
| this.addEventListener('click', this.handleClickOnPod_.bind(this)); |
| @@ -823,6 +829,10 @@ cr.define('login', function() { |
| this.imageElement.addEventListener('load', |
| this.parentNode.handlePodImageLoad.bind(this.parentNode, this)); |
| + this.smallPodImageElement.addEventListener( |
| + 'load', |
| + this.parentNode.handlePodImageLoad.bind(this.parentNode, this)); |
| + |
| var initialAuthType = this.user.initialAuthType || |
| AUTH_TYPE.OFFLINE_PASSWORD; |
| this.setAuthType(initialAuthType, null); |
| @@ -952,6 +962,22 @@ cr.define('login', function() { |
| }, |
| /** |
| + * Gets image element of the small pod. |
| + * @type {!HTMLImageElement} |
| + */ |
| + get smallPodImageElement() { |
| + return this.querySelector('.small-pod-image'); |
| + }, |
| + |
| + /** |
| + * Gets name element of the small pod. |
| + * @type {!HTMLDivElement} |
| + */ |
| + get smallPodNameElement() { |
| + return this.querySelector('.small-pod-name'); |
| + }, |
| + |
| + /** |
| * Gets reauth name hint element. |
| * @type {!HTMLDivElement} |
| */ |
| @@ -1123,14 +1149,14 @@ cr.define('login', function() { |
| */ |
| get statsMapElements() { |
| return { |
| - 'BrowsingHistory': |
| - this.querySelector('.action-box-remove-user-warning-history'), |
| - 'Passwords': |
| - this.querySelector('.action-box-remove-user-warning-passwords'), |
| - 'Bookmarks': |
| - this.querySelector('.action-box-remove-user-warning-bookmarks'), |
| - 'Settings': |
| - this.querySelector('.action-box-remove-user-warning-settings') |
| + 'BrowsingHistory': |
| + this.querySelector('.action-box-remove-user-warning-history'), |
|
jdufault
2017/05/23 20:34:32
revert?
Wenzhao (Colin) Zang
2017/05/24 00:29:21
Reverted. It's changed by style checker.
|
| + 'Passwords': |
| + this.querySelector('.action-box-remove-user-warning-passwords'), |
| + 'Bookmarks': |
| + this.querySelector('.action-box-remove-user-warning-bookmarks'), |
| + 'Settings': |
| + this.querySelector('.action-box-remove-user-warning-settings') |
| } |
| }, |
| @@ -1142,14 +1168,43 @@ cr.define('login', function() { |
| return this.querySelector('.fingerprint-icon-container'); |
| }, |
| + changeToLargePod: function() { |
| + this.querySelector('.large-pod').hidden = false; |
| + this.querySelector('.small-pod').hidden = true; |
| + }, |
| + |
| + changeToSmallPod: function() { |
| + this.querySelector('.large-pod').hidden = true; |
| + this.querySelector('.small-pod').hidden = false; |
| + this.querySelector('.small-pod').classList.remove('extra-small'); |
| + }, |
| + |
| + changeToExtraSmallPod: function() { |
| + this.querySelector('.large-pod').hidden = true; |
| + this.querySelector('.small-pod').hidden = false; |
| + this.querySelector('.small-pod').classList.add('extra-small'); |
| + }, |
| + |
| + isInLargeForm: function() { |
| + return this.querySelector('.small-pod').hidden; |
| + }, |
| + |
| + isInExtraSmallForm: function() { |
| + return this.querySelector('.small-pod').classList.contains('extra-small'); |
| + }, |
| + |
| /** |
| * Updates the user pod element. |
| */ |
| update: function() { |
| this.imageElement.src = 'chrome://userimage/' + this.user.username + |
| '?id=' + UserPod.userImageSalt_[this.user.username]; |
| + this.smallPodImageElement.src = 'chrome://userimage/' + |
|
jdufault
2017/05/23 20:34:32
Try to avoid redefining (non-trivial) strings mult
Wenzhao (Colin) Zang
2017/05/24 00:29:21
Done.
|
| + this.user.username + |
| + '?id=' + UserPod.userImageSalt_[this.user.username]; |
| this.nameElement.textContent = this.user_.displayName; |
| + this.smallPodNameElement.textContent = this.user_.displayName; |
| this.reauthNameHintElement.textContent = this.user_.displayName; |
| this.classList.toggle('signed-in', this.user_.signedIn); |
| @@ -1802,8 +1857,8 @@ cr.define('login', function() { |
| * @param {number|string=} count The number or string to replace $1 in |
| * |message|. Can be omitted if $1 is not present in |message|. |
| */ |
| - updateRemoveWarningDialogSetMessage_: function(profilePath, message, |
| - count) { |
| + updateRemoveWarningDialogSetMessage_: function( |
| + profilePath, message, count) { |
| if (profilePath !== this.user.profilePath) |
| return; |
| // Add localized messages where $1 will be replaced with |
| @@ -1987,7 +2042,8 @@ cr.define('login', function() { |
| * @param {Event} e The mouse down event. |
| */ |
| handlePodMouseDown_: function(e) { |
| - this.userClickAuthAllowed_ = this.parentNode.isFocused(this); |
| + if (this.isInLargeForm()) |
| + this.userClickAuthAllowed_ = this.parentNode.isFocused(this); |
| }, |
| /** |
| @@ -2044,6 +2100,12 @@ cr.define('login', function() { |
| if (this.parentNode.disabled) |
| return; |
| + if (!this.isInLargeForm()) { |
| + // It should trigger the switch between the small pod and the main pod. |
| + $('pod-row').changeMainPod_(this); |
| + return; |
| + } |
| + |
| if (!this.isActionBoxMenuActive) { |
| if (this.isAuthTypeOnlineSignIn) { |
| this.showSigninUI(); |
| @@ -2073,6 +2135,10 @@ cr.define('login', function() { |
| * @param {Event} e Key event. |
| */ |
| handlePodKeyDown_: function(e) { |
| + if (!this.isInLargeForm()) { |
| + this.handleSmallPodKeyDown_(e); |
| + return; |
| + } |
| if (!this.isAuthTypeUserClick || this.disabled) |
| return; |
| switch (e.key) { |
| @@ -2082,6 +2148,20 @@ cr.define('login', function() { |
| this.parentNode.setActivatedPod(this); |
| break; |
| } |
| + }, |
| + |
| + /** |
| + * Handles keydown event for a small user pod. |
| + * @param {Event} e Key event. |
| + */ |
| + handleSmallPodKeyDown_: function(e) { |
| + switch (e.key) { |
| + case 'Enter': |
| + case ' ': |
| + if ($('pod-row').isFocused(this)) |
| + $('pod-row').changeMainPod_(this); |
| + break; |
| + } |
| } |
| }; |
| @@ -2293,6 +2373,12 @@ cr.define('login', function() { |
| if (this.parentNode.disabled) |
| return; |
| + if (!this.isInLargeForm()) { |
| + // It should trigger the switch between the small pod and the main pod. |
| + $('pod-row').changeMainPod_(this); |
|
jdufault
2017/05/23 20:34:32
changeMainPod_ seems like it should be a public (i
Wenzhao (Colin) Zang
2017/05/24 00:29:20
The underscore is removed. I'm open to rename it b
|
| + return; |
| + } |
| + |
| this.parentNode.focusPod(this); |
| this.parentNode.setActivatedPod(this, e); |
|
jdufault
2017/05/23 20:34:32
If you remove these two calls, does anything break
Wenzhao (Colin) Zang
2017/05/24 00:29:20
The two calls must be kept for 'large' pods.
They
|
| // Prevent default so that we don't trigger 'focus' event. |
| @@ -2526,7 +2612,9 @@ cr.define('login', function() { |
| /** @override */ |
| update: function() { |
| this.imageElement.src = this.user.userImage; |
| + this.smallPodImageElement.src = this.user.userImage; |
| this.nameElement.textContent = this.user.displayName; |
| + this.smallPodNameElement.textContent = this.user.displayName; |
| this.reauthNameHintElement.textContent = this.user.displayName; |
| var isLockedUser = this.user.needsSignin; |
| @@ -2571,6 +2659,12 @@ cr.define('login', function() { |
| if (this.parentNode.disabled) |
| return; |
| + if (!this.isInLargeForm()) { |
| + // It should trigger the switch between the small pod and the main pod. |
| + $('pod-row').changeMainPod_(this); |
| + return; |
| + } |
| + |
| Oobe.clearErrors(); |
| this.parentNode.lastFocusedPod_ = this; |
| @@ -2612,9 +2706,13 @@ cr.define('login', function() { |
| this.imageElement.src = this.user.iconUrl; |
| this.imageElement.alt = this.user.label; |
| this.imageElement.title = this.user.label; |
| + this.smallPodImageElement.src = this.user.iconUrl; |
| + this.smallPodImageElement.alt = this.user.label; |
| + this.smallPodImageElement.title = this.user.label; |
| this.passwordEntryContainerElement.hidden = true; |
| this.launchAppButtonContainerElement.hidden = false; |
| this.nameElement.textContent = this.user.label; |
| + this.smallPodNameElement.textContent = this.user.label; |
| this.reauthNameHintElement.textContent = this.user.label; |
| UserPod.prototype.updateActionBoxArea.call(this); |
| @@ -2651,6 +2749,12 @@ cr.define('login', function() { |
| if (this.parentNode.disabled) |
| return; |
| + if (!this.isInLargeForm()) { |
| + // It should trigger the switch between the small pod and the main pod. |
| + $('pod-row').changeMainPod_(this); |
| + return; |
| + } |
| + |
| Oobe.clearErrors(); |
| this.parentNode.lastFocusedPod_ = this; |
| this.activate(e); |
| @@ -2712,6 +2816,9 @@ cr.define('login', function() { |
| // Pod that was most recently focused, if any. |
| lastFocusedPod_: undefined, |
| + // Pod that occupies the main spot. |
| + mainPod_: undefined, |
| + |
| // Pods whose initial images haven't been loaded yet. |
| podsWithPendingImages_: [], |
| @@ -2759,11 +2866,15 @@ cr.define('login', function() { |
| }, |
| /** |
| - * Returns all the pods in this pod row. |
| + * Returns all the pods in this pod row. Some pods may not be its direct |
| + * children, but the caller doesn't have to know this. |
| * @type {NodeList} |
| */ |
| get pods() { |
| - return Array.prototype.slice.call(this.children); |
| + var powRowChildren = Array.prototype.slice.call(this.children); |
| + var containerChildren = |
| + Array.prototype.slice.call(this.smallPodsContainer.children); |
| + return powRowChildren.concat(containerChildren); |
| }, |
| /** |
| @@ -2776,7 +2887,8 @@ cr.define('login', function() { |
| DISPLAY_TYPE.DESKTOP_USER_MANAGER; |
| return (isDesktopUserManager || this.touchViewEnabled_) ? |
| - false : this.children.length == 1; |
| + false : |
| + this.pods.length == 1; |
| }, |
| /** |
| @@ -2953,9 +3065,12 @@ cr.define('login', function() { |
| console.warn('Attempt to remove pod that does not exist'); |
| return; |
| } |
| - this.removeChild(podToRemove); |
| - if (this.pods.length > 0) |
| + podToRemove.parentNode.removeChild(podToRemove); |
| + this.mainPod_ = null; |
| + if (this.pods.length > 0) { |
| this.placePods_(); |
| + this.maybePreselectPod(); |
| + } |
| }, |
| /** |
| @@ -3024,7 +3139,6 @@ cr.define('login', function() { |
| // Switch off animation |
| Oobe.getInstance().toggleClass('flying-pods', false); |
| - // Populate the pod row. |
| for (var i = 0; i < this.users_.length; ++i) |
| this.addUserPod(this.users_[i]); |
| @@ -3070,6 +3184,14 @@ cr.define('login', function() { |
| }, |
| /** |
| + * Gets the container of small pods. |
| + * @type {!HTMLDivElement} |
| + */ |
| + get smallPodsContainer() { |
| + return document.querySelector('.small-pod-container'); |
| + }, |
| + |
| + /** |
| * Adds given apps to the pod row. |
| * @param {array} apps Array of apps. |
| */ |
| @@ -3322,10 +3444,8 @@ cr.define('login', function() { |
| * @param {boolean} multipleRecommendedLocales Whether |locales| contains |
| * two or more recommended locales |
| */ |
| - setPublicSessionLocales: function(userID, |
| - locales, |
| - defaultLocale, |
| - multipleRecommendedLocales) { |
| + setPublicSessionLocales: function( |
| + userID, locales, defaultLocale, multipleRecommendedLocales) { |
| var pod = this.getPodWithUsername_(userID); |
| if (pod != null) { |
| pod.populateLanguageSelect(locales, |
| @@ -3351,23 +3471,7 @@ cr.define('login', function() { |
| * Called when window was resized. |
| */ |
| onWindowResize: function() { |
|
jdufault
2017/05/23 20:34:32
Did you test with virtual keyboard?
Wenzhao (Colin) Zang
2017/05/24 00:29:20
I did. It works, but has bugs related to the backg
|
| - var layout = this.calculateLayout_(); |
| - if (layout.columns != this.columns || layout.rows != this.rows) |
| - this.placePods_(); |
| - |
| - // Wrap this in a set timeout so the function is called after the pod is |
| - // finished transitioning so that we work with the final pod dimensions. |
| - // If there is no focused pod that may be transitioning when this function |
| - // is called, we can call scrollFocusedPodIntoView() right away. |
| - var timeOut = 0; |
| - if (this.focusedPod_) { |
| - var style = getComputedStyle(this.focusedPod_); |
| - timeOut = parseFloat(style.transitionDuration) * 1000; |
| - } |
| - |
| - setTimeout(function() { |
| - this.scrollFocusedPodIntoView(); |
| - }.bind(this), timeOut); |
| + this.placePods_(); |
| }, |
| /** |
| @@ -3418,68 +3522,357 @@ cr.define('login', function() { |
| if (!Oobe.getInstance().newDesktopUserManager) { |
| var maxHeigth = Oobe.getInstance().clientAreaSize.height; |
| while (maxHeigth < this.rowsToHeight_(rows) && rows > 1) |
| - --rows; |
| + --rows; |
| } |
| // One more iteration if it's not enough cells to place all pods. |
| while (maxWidth >= this.columnsToWidth_(columns + 1) && |
| columns * rows < this.pods.length && |
| columns < MAX_NUMBER_OF_COLUMNS) { |
| - ++columns; |
| + ++columns; |
| } |
| return {columns: columns, rows: rows}; |
| }, |
| /** |
| - * Places pods onto their positions onto pod grid. |
| + * Places pods onto their positions in pod grid matching the new design. |
| * @private |
| */ |
| placePods_: function() { |
| - var isDesktopUserManager = Oobe.getInstance().displayType == |
| - DISPLAY_TYPE.DESKTOP_USER_MANAGER; |
| - if (isDesktopUserManager && !Oobe.getInstance().userPodsPageVisible) |
| + var pods = this.pods; |
| + if (pods.length == 0) { |
| + console.error('Attempt to place pods for an empty pod list.'); |
| return; |
| + } |
| + // Append all pods to their proper parents. Small pods have parent other |
| + // than the pod row. The pods were all initialized with the pow row as a |
| + // temporary parent, which is intended to ensure that all event listeners |
| + // work properly. If the main pod already exists, it means we are in the |
| + // process of resizing the window, then there is no need to change parents |
| + // of any pod. |
| + if (!this.mainPod_) { |
| + this.mainPod_ = this.preselectedPod; |
| + this.appendPodsToParents(); |
| + } |
| + this.restoreInitialStates_(); |
| - var layout = this.calculateLayout_(); |
| - var columns = this.columns = layout.columns; |
| - var rows = this.rows = layout.rows; |
| - var maxPodsNumber = columns * rows; |
| - var margin = isDesktopUserManager ? DESKTOP_MARGIN_BY_COLUMNS[columns] : |
| - MARGIN_BY_COLUMNS[columns]; |
| - this.parentNode.setPreferredSize( |
| - this.columnsToWidth_(columns), this.rowsToHeight_(rows)); |
| - var height = this.userPodHeight_; |
| - var width = this.userPodWidth_; |
| - var pinPodLocation = { column: columns + 1, row: rows + 1 }; |
| - if (this.focusedPod_ && this.focusedPod_.isPinShown()) |
| - pinPodLocation = this.findPodLocation_(this.focusedPod_, columns, rows); |
| + if (pods.length == 1) { |
| + this.placeSinglePod_(); |
| + } else if (pods.length == 2) { |
| + this.placeDoublePods_(); |
| + } else { |
| + this.placePodsOnContainer_(); |
| + } |
| + Oobe.getInstance().updateScreenSize(this.parentNode); |
| + this.updatePodNameArea(); |
| + }, |
| - this.pods.forEach(function(pod, index) { |
| - if (index >= maxPodsNumber) { |
| - pod.hidden = true; |
| - return; |
| + /** |
| + * Append pods to proper parents. Called each time before pod placement. |
| + * @private |
| + */ |
| + appendPodsToParents: function() { |
| + var pods = this.pods; |
| + // Pod count may have changed, remove all pods from their current parents |
| + // first. |
| + for (var i = 0, pod; pod = pods[i]; ++i) { |
|
jdufault
2017/05/23 20:34:32
for (var pod of pods)?
Wenzhao (Colin) Zang
2017/05/24 00:29:20
Done.
|
| + pod.parentNode.removeChild(pod); |
| + } |
| + |
| + if (pods.length <= 2) { |
|
jdufault
2017/05/23 20:34:32
Add comment on the 2 / make it a constant
Wenzhao (Colin) Zang
2017/05/24 00:29:20
Done.
|
| + for (var i = 0, pod; pod = pods[i]; ++i) { |
| + this.appendChild(pod); |
| + } |
| + } else { |
| + for (var i = 0, pod; pod = pods[i]; ++i) { |
| + if (pod == this.mainPod_) { |
| + this.appendChild(pod); |
| + } else { |
| + this.smallPodsContainer.appendChild(pod); |
| + } |
| + } |
| + } |
| + }, |
| + |
| + /** |
| + * Called when there is one user. |
| + * @private |
| + */ |
| + placeSinglePod_: function() { |
| + this.mainPod_.changeToLargePod(); |
| + this.parentNode.setPreferredSize(CROS_POD_WIDTH, CROS_POD_HEIGHT); |
| + // The pod may have different positions before, so always set them |
| + // explicitly. |
| + this.mainPod_.left = 0; |
| + this.mainPod_.top = 0; |
| + }, |
| + |
| + /** |
| + * Called when there are two users. |
| + * @private |
| + */ |
| + placeDoublePods_: function() { |
| + var secondPod = |
| + this.pods[0] == this.mainPod_ ? this.pods[1] : this.pods[0]; |
| + this.mainPod_.changeToLargePod(); |
| + secondPod.changeToLargePod(); |
| + |
| + var DOUBLE_PODS_PADDING = this.isPortraitMode() ? 32 : 118; |
| + var parentWidth = CROS_POD_WIDTH * 2 + DOUBLE_PODS_PADDING; |
| + this.parentNode.setPreferredSize(parentWidth, CROS_POD_HEIGHT); |
| + |
| + this.mainPod_.left = 0; |
| + this.mainPod_.top = 0; |
| + secondPod.left = CROS_POD_WIDTH + DOUBLE_PODS_PADDING; |
| + secondPod.top = 0; |
| + }, |
| + |
| + /** |
| + * Called when there are more than two users. |
| + * @private |
| + */ |
| + placePodsOnContainer_: function() { |
| + this.smallPodsContainer.hidden = false; |
| + var pods = this.pods; |
| + if ((pods.length > 6 && !this.isPortraitMode()) || |
|
jdufault
2017/05/23 20:34:32
constant for 6 and 10
Wenzhao (Colin) Zang
2017/05/24 00:29:21
Done.
|
| + (pods.length > 10 && this.isPortraitMode())) { |
| + this.placePodsOnScrollableContainer_(); |
| + return; |
| + } |
| + |
| + var MIDDLE_PADDING = this.isPortraitMode() ? 84 : 220; |
| + var portraitWidth = |
| + CROS_POD_WIDTH + MIDDLE_PADDING + CROS_SMALL_POD_WIDTH; |
| + var LEFT_PADDING = this.isPortraitMode() ? |
| + (Oobe.getInstance().clientAreaSize.width - portraitWidth) / 3 : |
| + 98; |
| + var SMALL_POD_PADDING = 54; |
| + var smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT + |
| + (pods.length - 2) * SMALL_POD_PADDING; |
| + var parentHeight = Math.max(CROS_POD_HEIGHT, smallPodsTotalHeight); |
| + if (parentHeight > Oobe.getInstance().clientAreaSize.height) { |
| + // The current design spec assumes the screen height is large enough, |
| + // but if it's not, fall to the scrollable container case. We do not |
| + // have a backup solution yet if the screen width is exceeded. |
| + this.placePodsOnScrollableContainer_(); |
| + return; |
| + } |
| + this.smallPodsContainer.style.height = |
| + cr.ui.toCssPx(Oobe.getInstance().clientAreaSize.height); |
| + this.smallPodsContainer.style.width = cr.ui.toCssPx(CROS_SMALL_POD_WIDTH); |
| + var parentWidth = |
| + LEFT_PADDING + CROS_POD_WIDTH + MIDDLE_PADDING + CROS_SMALL_POD_WIDTH; |
| + this.parentNode.setPreferredSize(parentWidth, parentHeight); |
| + |
| + this.mainPod_.changeToLargePod(); |
| + for (var i = 0, pod; pod = pods[i]; ++i) { |
| + if (pod != this.mainPod_) { |
| + pod.changeToSmallPod(); |
| + } |
| + } |
| + this.mainPod_.left = LEFT_PADDING; |
| + this.mainPod_.top = |
| + Math.max((smallPodsTotalHeight - CROS_POD_HEIGHT) / 2, 0); |
| + this.smallPodsContainer.style.left = |
| + cr.ui.toCssPx(LEFT_PADDING + CROS_POD_WIDTH + MIDDLE_PADDING); |
| + this.smallPodsContainer.style.top = cr.ui.toCssPx( |
| + Math.max((CROS_POD_HEIGHT - smallPodsTotalHeight) / 2, 0)); |
| + var topPadding = 0; |
| + for (var i = 0, pod; pod = pods[i]; ++i) { |
| + if (pod == this.mainPod_) { |
| + continue; |
| + } |
| + pod.left = 0; |
| + pod.top = topPadding; |
| + topPadding += CROS_SMALL_POD_HEIGHT + SMALL_POD_PADDING; |
| + } |
| + }, |
| + |
| + /** |
| + * Called when there are more than 6 users in landscape mode, or more than |
| + * 10 users in portrait mode. |
| + * @private |
| + */ |
| + placePodsOnScrollableContainer_: function() { |
| + this.smallPodsContainer.hidden = false; |
| + this.smallPodsContainer.classList.add('scroll'); |
| + var pods = this.pods; |
| + this.mainPod_.changeToLargePod(); |
| + for (var i = 0, pod; pod = pods[i]; ++i) { |
| + if (pod != this.mainPod_) { |
| + pod.changeToExtraSmallPod(); |
| } |
| - pod.hidden = false; |
| - if (pod.offsetHeight != height && |
| - pod.offsetHeight != CROS_PIN_POD_HEIGHT) { |
| - console.error('Pod offsetHeight (' + pod.offsetHeight + |
| - ') and POD_HEIGHT (' + height + ') are not equal.'); |
| + } |
| + |
| + var SCROLL_LEFT_PADDING = this.isPortraitMode() ? 46 : 72; |
| + var SCROLL_RIGHT_PADDING = this.isPortraitMode() ? 12 : 72; |
| + var scrollAreaWidth = SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH + |
| + SCROLL_RIGHT_PADDING; |
| + var mainPodPadding = (Oobe.getInstance().clientAreaSize.width - |
| + scrollAreaWidth - CROS_POD_WIDTH) / |
| + 2; |
| + var SCROLL_TOP_PADDING = this.isPortraitMode() ? 66 : 72; |
| + var EXTRA_SMALL_POD_PADDING = 32; |
| + this.smallPodsContainer.style.left = |
| + cr.ui.toCssPx(mainPodPadding * 2 + CROS_POD_WIDTH); |
| + this.smallPodsContainer.style.top = cr.ui.toCssPx(0); |
| + |
| + var scrollHeight = 0; |
| + for (var i = 0, pod; pod = pods[i]; ++i) { |
| + if (pod == this.mainPod_) { |
| + continue; |
| } |
| - if (pod.offsetWidth != width) { |
| - console.error('Pod offsetWidth (' + pod.offsetWidth + |
| - ') and POD_WIDTH (' + width + ') are not equal.'); |
| + scrollHeight += CROS_EXTRA_SMALL_POD_HEIGHT + EXTRA_SMALL_POD_PADDING; |
| + } |
| + scrollHeight -= EXTRA_SMALL_POD_PADDING; |
| + var screenHeight = |
| + document.querySelector('#scroll-container').offsetHeight; |
| + var actualTopPadding = SCROLL_TOP_PADDING; |
| + this.smallPodsContainer.style.width = cr.ui.toCssPx( |
| + SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH + |
| + SCROLL_RIGHT_PADDING); |
| + this.smallPodsContainer.style.height = cr.ui.toCssPx(screenHeight); |
| + if ((screenHeight - scrollHeight) / 2 > actualTopPadding) { |
| + // Edge case: the contents don't overflow because the pods were |
| + // shrinked. In this case the top padding should be adjusted to have a |
| + // symmetric layout. |
| + actualTopPadding = (screenHeight - scrollHeight) / 2; |
| + } else { |
| + // The scrollable container should occupy the full screen (including the |
| + // header bar) and a gradient mask is applied to avoid blocking the |
| + // header bar. |
| + actualTopPadding = SCROLL_MASK_HEIGHT; |
| + this.showScrollMask(); |
| + } |
| + this.parentNode.setPreferredSize( |
| + Oobe.getInstance().clientAreaSize.width, |
| + Oobe.getInstance().clientAreaSize.height); |
| + this.mainPod_.left = mainPodPadding; |
| + this.mainPod_.top = (screenHeight - CROS_POD_HEIGHT) / 2; |
| + |
| + var topPadding = actualTopPadding; |
| + var lastPod = undefined; |
| + for (var i = 0, pod; pod = pods[i]; ++i) { |
| + if (pod == this.mainPod_) { |
| + continue; |
| } |
| - var column = index % columns; |
| - var row = Math.floor(index / columns); |
| + pod.left = SCROLL_LEFT_PADDING; |
| + pod.top = topPadding; |
| + topPadding += CROS_EXTRA_SMALL_POD_HEIGHT + EXTRA_SMALL_POD_PADDING; |
| + lastPod = pod; |
| + } |
| + if (!document.querySelector('.small-pod-container-mask').hidden) { |
| + // Make sure the last pod isn't blocked by the mask. |
| + lastPod.style.paddingBottom = cr.ui.toCssPx(SCROLL_MASK_HEIGHT); |
| + } |
| + }, |
| - var rowPadding = isDesktopUserManager ? DESKTOP_ROW_PADDING : |
| - POD_ROW_PADDING; |
| - pod.left = rowPadding + column * (width + margin); |
| + /** |
| + * Called each time before pod placement to ensure we start with a clean |
| + * state. |
| + * @private |
| + */ |
| + restoreInitialStates_: function() { |
| + this.smallPodsContainer.hidden = true; |
| + document.querySelector('.small-pod-container-mask').hidden = true; |
| + document.querySelector('.small-pod-container-mask.rotate').hidden = true; |
| + this.smallPodsContainer.classList.remove('scroll'); |
| + var pods = this.pods; |
| + for (var i = 0, pod; pod = pods[i]; ++i) { |
| + pod.style.paddingBottom = cr.ui.toCssPx(0); |
| + } |
| + }, |
| + |
| + /** |
| + * Check if it's in portrait mode. |
| + * @return {boolean} True if in portrait mode. |
| + */ |
| + isPortraitMode: function() { |
| + return Oobe.getInstance().clientAreaSize.width < |
| + Oobe.getInstance().clientAreaSize.height; |
| + }, |
| - // On desktop, we want the rows to always be equally spaced. |
| - pod.top = isDesktopUserManager ? row * (height + rowPadding) : |
| - row * height + rowPadding; |
| + /** |
| + * Called when scroll bar is shown and we need a mask for the header bar. |
| + * @private |
| + */ |
| + showScrollMask: function() { |
| + var topMask = document.querySelector('.small-pod-container-mask'); |
| + topMask.hidden = false; |
| + topMask.style.left = this.smallPodsContainer.style.left; |
| + topMask.style.width = this.smallPodsContainer.style.width; |
| + var bottomMask = |
| + document.querySelector('.small-pod-container-mask.rotate'); |
| + bottomMask.hidden = false; |
| + bottomMask.style.left = this.smallPodsContainer.style.left; |
| + bottomMask.style.width = this.smallPodsContainer.style.width; |
| + // The bottom mask should overlap with the header bar. |
| + bottomMask.style.top = cr.ui.toCssPx( |
| + document.querySelector('#scroll-container').offsetHeight - |
| + SCROLL_MASK_HEIGHT); |
| + }, |
| + |
| + /** |
| + * Makes sure that user name on each large pod is centered and extra long |
| + * name does not exceed max width. |
| + * @private |
| + */ |
| + updatePodNameArea: function() { |
| + this.querySelectorAll('.name-container').forEach(function(nameArea) { |
| + var nameElement = nameArea.querySelector('.name'); |
| + var leftMargin = (CROS_POD_WIDTH - nameElement.offsetWidth) / 2; |
| + if (leftMargin > 0) |
| + nameArea.style.left = cr.ui.toCssPx(leftMargin); |
| + else |
| + nameElement.style.width = cr.ui.toCssPx(CROS_POD_WIDTH); |
| }); |
| - Oobe.getInstance().updateScreenSize(this.parentNode); |
| + }, |
| + |
| + /** |
| + * Called when a small pod is clicked to trigger the switch between the |
| + * small pod and the main pod. |
| + */ |
| + changeMainPod_: function(pod) { |
| + if (this.disabled) { |
| + console.error('Cannot change main pod while sign-in UI is disabled.'); |
| + return; |
| + } |
| + if (!this.mainPod_) { |
| + console.error('Attempt to switch a non-existing main pod.'); |
| + return; |
| + } |
| + var insert = 0; |
| + var children = pod.parentNode.children; |
| + while (insert < children.length && children[insert] != pod) |
| + insert++; |
| + if (insert >= children.length) { |
| + console.error('Attempt to switch a non-existing small pod.'); |
| + return; |
| + } |
| + if (pod.isInExtraSmallForm()) { |
|
jdufault
2017/05/23 20:34:32
Instead of having separate functions for isExtraSm
Wenzhao (Colin) Zang
2017/05/24 00:29:20
Done.
|
| + this.mainPod_.changeToExtraSmallPod(); |
| + } else { |
| + this.mainPod_.changeToSmallPod(); |
| + } |
| + pod.changeToLargePod(); |
| + |
| + var left = pod.left; |
| + var top = pod.top; |
| + var paddingBottom = pod.style.paddingBottom; |
| + var parent = pod.parentNode; |
| + parent.removeChild(pod); |
| + this.appendChild(pod); |
| + pod.left = this.mainPod_.left; |
| + pod.top = this.mainPod_.top; |
| + pod.style.paddingBottom = cr.ui.toCssPx(0); |
| + |
| + this.removeChild(this.mainPod_); |
| + parent.insertBefore(this.mainPod_, children[insert]); |
| + this.mainPod_.left = left; |
| + this.mainPod_.top = top; |
| + this.mainPod_.style.paddingBottom = paddingBottom; |
| + this.mainPod_ = pod; |
| + this.focusPod(this.mainPod_); |
| + this.updatePodNameArea(); |
| }, |
| /** |
| @@ -3803,6 +4196,12 @@ cr.define('login', function() { |
| return; |
| } |
| + // Small pods do not have input box. |
| + if (e.target.parentNode == this.smallPodsContainer) { |
| + this.focusPod(e.target, false, true /* opt_skipInputFocus */); |
| + return; |
| + } |
| + |
| var pod = findAncestorByClass(e.target, 'pod'); |
| if (pod && pod.parentNode == this) { |
| // Focus on a control of a pod but not on the action area button. |
| @@ -3963,33 +4362,18 @@ cr.define('login', function() { |
| }, |
| /** |
| - * Makes sure user name is centered in each pod and extra long name |
| - * does not exceed max width. |
| - */ |
| - updatePodNameArea: function() { |
| - this.querySelectorAll('.name-container').forEach(function(nameArea) { |
| - var nameElement = nameArea.querySelector('.name'); |
| - var leftMargin = (CROS_POD_WIDTH - nameElement.offsetWidth) / 2; |
| - if (leftMargin > 0) |
| - nameArea.style.left = leftMargin + 'px'; |
| - else |
| - nameElement.style.width = CROS_POD_WIDTH + 'px'; |
| - }); |
| - }, |
| - |
| - /** |
| * Preselects pod, if needed. |
| */ |
| - maybePreselectPod: function() { |
| - var pod = this.preselectedPod; |
| - this.focusPod(pod); |
| + maybePreselectPod: function() { |
| + var pod = this.preselectedPod; |
| + this.focusPod(pod); |
| - // Hide user-type-bubble in case all user pods are disabled and we focus |
| - // first pod. |
| - if (pod && pod.multiProfilesPolicyApplied) { |
| - pod.userTypeBubbleElement.classList.remove('bubble-shown'); |
| - } |
| - } |
| + // Hide user-type-bubble in case all user pods are disabled and we focus |
| + // first pod. |
| + if (pod && pod.multiProfilesPolicyApplied) { |
| + pod.userTypeBubbleElement.classList.remove('bubble-shown'); |
| + } |
| + } |
| }; |
| return { |