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

Unified Diff: ui/login/account_picker/md_user_pod_row.js

Issue 2898283002: Multiple user pods implementation for new login screen (Closed)
Patch Set: Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
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 {

Powered by Google App Engine
This is Rietveld 408576698