Index: ui/login/account_picker/user_pod_row.js |
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js |
index 39b5c7deb584276ab1a5769e32490ec3bf3abc69..e83344b2bb6f31911e7e9316ffa64b8740b5ef83 100644 |
--- a/ui/login/account_picker/user_pod_row.js |
+++ b/ui/login/account_picker/user_pod_row.js |
@@ -85,10 +85,11 @@ cr.define('login', function() { |
* @const |
*/ |
var UserPodTabOrder = { |
- POD_INPUT: 1, // Password input fields (and whole pods themselves). |
- HEADER_BAR: 2, // Buttons on the header bar (Shutdown, Add User). |
- ACTION_BOX: 3, // Action box buttons. |
- PAD_MENU_ITEM: 4 // User pad menu items (Remove this user). |
+ POD_INPUT: 1, // Password input fields (and whole pods themselves). |
+ POD_CUSTOM_ICON: 2, // Pod custom icon next to passwrod input field. |
+ HEADER_BAR: 3, // Buttons on the header bar (Shutdown, Add User). |
+ ACTION_BOX: 4, // Action box buttons. |
+ PAD_MENU_ITEM: 5 // User pad menu items (Remove this user). |
}; |
/** |
@@ -103,6 +104,7 @@ cr.define('login', function() { |
NUMERIC_PIN: 2, |
USER_CLICK: 3, |
EXPAND_THEN_USER_CLICK: 4, |
+ FORCE_OFFLINE_PASSWORD: 5 |
}; |
/** |
@@ -114,6 +116,7 @@ cr.define('login', function() { |
2: 'numericPin', |
3: 'userClick', |
4: 'expandThenUserClick', |
+ 5: 'forceOfflinePassword' |
}; |
// Focus and tab order are organized as follows: |
@@ -121,9 +124,12 @@ 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) buttons on the header bar have tab index 2 so they follow user pods; |
- // (4) Action box buttons have tab index 3 and follow header bar buttons; |
- // (5) lastly, focus jumps to the Status Area and back to user pods. |
+ // (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. |
// |
// 'Focus' event is handled by a capture handler for the whole document |
// and in some cases 'mousedown' event handlers are used instead of 'click' |
@@ -252,6 +258,23 @@ cr.define('login', function() { |
*/ |
animationResourceSize_: 0, |
+ /** |
+ * When {@code fadeOut} is called, the element gets hidden using fadeout |
+ * animation. This is reference to the listener for transition end added to |
+ * the icon element while it's fading out. |
+ * @type {?function(Event)} |
+ * @private |
+ */ |
+ hideTransitionListener_: null, |
+ |
+ /** |
+ * Callback for click and 'Enter' key events that gets set if the icon is |
+ * interactive. |
+ * @type {?function()} |
+ * @private |
+ */ |
+ actionHandler_: null, |
+ |
/** @override */ |
decorate: function() { |
this.iconElement.addEventListener('mouseover', |
@@ -260,6 +283,16 @@ cr.define('login', function() { |
this.hideTooltip_.bind(this, false)); |
this.iconElement.addEventListener('mousedown', |
this.hideTooltip_.bind(this, false)); |
+ this.iconElement.addEventListener('click', |
+ this.handleClick_.bind(this)); |
+ this.iconElement.addEventListener('keydown', |
+ this.handleKeyDown_.bind(this)); |
+ |
+ // When the icon is focused using mouse, there should be no outline shown. |
+ // Preventing default mousedown event accomplishes this. |
+ this.iconElement.addEventListener('mousedown', function(e) { |
+ e.preventDefault(); |
+ }); |
}, |
/** |
@@ -298,16 +331,24 @@ cr.define('login', function() { |
* Shows the icon. |
*/ |
show: function() { |
+ this.resetHideTransitionState_(); |
this.hidden = false; |
}, |
/** |
- * Hides the icon. Makes sure the tooltip is hidden and animation reset. |
+ * Hides the icon using a fade-out animation. |
*/ |
- hide: function() { |
+ fadeOut: function() { |
+ // The icon is already being hidden. |
+ if (this.iconElement.classList.contains('faded')) |
+ return; |
+ |
this.hideTooltip_(true); |
- this.setAnimation(null); |
- this.hidden = true; |
+ this.iconElement.classList.add('faded'); |
+ this.hideTransitionListener_ = this.hide_.bind(this); |
+ this.iconElement.addEventListener('webkitTransitionEnd', |
+ this.hideTransitionListener_); |
+ ensureTransitionEndEvent(this.iconElement, 200); |
}, |
/** |
@@ -403,6 +444,80 @@ cr.define('login', function() { |
}, |
/** |
+ * Sets up icon tabIndex attribute and handler for click and 'Enter' key |
+ * down events. |
+ * @param {?function()} callback If icon should be interactive, the |
+ * function to get called on click and 'Enter' key down events. Should |
+ * be null to make the icon non interactive. |
+ */ |
+ setInteractive: function(callback) { |
+ // Update tabIndex property if needed. |
+ if (!!this.actionHandler_ != !!callback) { |
+ if (callback) { |
+ this.iconElement.setAttribute('tabIndex', |
+ UserPodTabOrder.POD_CUSTOM_ICON); |
+ } else { |
+ this.iconElement.removeAttribute('tabIndex'); |
+ } |
+ } |
+ |
+ // Set the new action handler. |
+ this.actionHandler_ = callback; |
+ }, |
+ |
+ /** |
+ * Hides the icon. Makes sure the tooltip is hidden and animation reset. |
+ * @private |
+ */ |
+ hide_: function() { |
+ this.hideTooltip_(true); |
+ this.hidden = true; |
+ this.setAnimation(null); |
+ this.setInteractive(null); |
+ this.resetHideTransitionState_(); |
+ }, |
+ |
+ /** |
+ * Ensures the icon's transition state potentially set by a call to |
+ * {@code fadeOut} is cleared. |
+ * @private |
+ */ |
+ resetHideTransitionState_: function() { |
+ if (this.hideTransitionListener_) { |
+ this.iconElement.removeEventListener('webkitTransitionEnd', |
+ this.hideTransitionListener_); |
+ this.hideTransitionListener_ = null; |
+ } |
+ this.iconElement.classList.toggle('faded', false); |
+ }, |
+ |
+ /** |
+ * Handles click event on the icon element. No-op if |
+ * {@code this.actionHandler_} is not set. |
+ * @param {Event} e The click event. |
+ * @private |
+ */ |
+ handleClick_: function(e) { |
+ if (!this.actionHandler_) |
+ return; |
+ this.actionHandler_(); |
+ stopEventPropagation(e); |
+ }, |
+ |
+ /** |
+ * Handles key down event on the icon element. Only 'Enter' key is handled. |
+ * No-op if {@code this.actionHandler_} is not set. |
+ * @param {Event} e The key down event. |
+ * @private |
+ */ |
+ handleKeyDown_: function(e) { |
+ if (!this.actionHandler_ || e.keyIdentifier != 'Enter') |
+ return; |
+ this.actionHandler_(e); |
+ stopEventPropagation(e); |
+ }, |
+ |
+ /** |
* Called when mouse enters the icon. It sets timeout for showing the |
* tooltip. |
* @private |
@@ -415,7 +530,7 @@ cr.define('login', function() { |
}, |
/** |
- * Shows the current tooltip, if one is set. |
+ * Shows the current tooltip if one is set. |
* @private |
*/ |
showTooltip_: function() { |
@@ -973,7 +1088,8 @@ cr.define('login', function() { |
* @type {bool} |
*/ |
get isAuthTypePassword() { |
- return this.authType_ == AUTH_TYPE.OFFLINE_PASSWORD; |
+ return this.authType_ == AUTH_TYPE.OFFLINE_PASSWORD || |
+ this.authType_ == AUTH_TYPE.FORCE_OFFLINE_PASSWORD; |
}, |
/** |
@@ -2199,6 +2315,12 @@ cr.define('login', function() { |
pod.customIconElement.setSize(icon.size || {width: 0, height: 0}); |
pod.customIconElement.setAnimation(icon.animation || null); |
pod.customIconElement.setOpacity(icon.opacity || 100); |
+ if (icon.hardlockOnClick) { |
+ pod.customIconElement.setInteractive( |
+ this.hardlockUserPod_.bind(this, username)); |
+ } else { |
+ pod.customIconElement.setInteractive(null); |
+ } |
pod.customIconElement.show(); |
// This has to be called after |show| in case the tooltip should be shown |
// immediatelly. |
@@ -2207,6 +2329,17 @@ cr.define('login', function() { |
}, |
/** |
+ * Hard-locks user pod for the user. If user pod is hard-locked, it can be |
+ * only unlocked using password, and the authentication type cannot be |
+ * changed. |
+ * @param {!string} username The user's username. |
+ * @private |
+ */ |
+ hardlockUserPod_: function(username) { |
+ chrome.send('hardlockPod', [username]); |
+ }, |
+ |
+ /** |
* Hides the custom icon in the user pod added by showUserPodCustomIcon(). |
* @param {string} username Username of pod to remove button |
*/ |
@@ -2218,7 +2351,7 @@ cr.define('login', function() { |
return; |
} |
- pod.customIconElement.hide(); |
+ pod.customIconElement.fadeOut(); |
}, |
/** |