Chromium Code Reviews| Index: chrome/browser/resources/chromeos/login/user_pod_row.js |
| diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.js b/chrome/browser/resources/chromeos/login/user_pod_row.js |
| index b5090e0424bd942789f72461b2c5e805a467315f..47f0d112b93d535d3bc50885d5cdb209a6a66def 100644 |
| --- a/chrome/browser/resources/chromeos/login/user_pod_row.js |
| +++ b/chrome/browser/resources/chromeos/login/user_pod_row.js |
| @@ -37,8 +37,8 @@ cr.define('login', function() { |
| var MAX_NUMBER_OF_ROWS_UNDER_SIGNIN_BANNER = 2; |
| /** |
| - * Variables used for pod placement processing. |
| - * Width and height should be synced with computed CSS sizes of pods. |
| + * Variables used for pod placement processing. Width and height should be |
| + * synced with computed CSS sizes of pods. |
| */ |
| var POD_WIDTH = 180; |
| var POD_HEIGHT = 217; |
| @@ -82,7 +82,7 @@ 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; |
| + // 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. |
| @@ -258,14 +258,22 @@ cr.define('login', function() { |
| }, |
| /** |
| - * Gets user signin button. |
| - * @type {!HTMLInputElement} |
| + * Gets user sign in button. |
| + * @type {!HTMLButtonElement} |
| */ |
| get signinButtonElement() { |
| return this.querySelector('.signin-button'); |
| }, |
| /** |
| + * Gets launch app button. |
| + * @type {!HTMLButtonElement} |
| + */ |
| + get launchAppButtonElement() { |
| + return this.querySelector('.launch-app-button'); |
| + }, |
| + |
| + /** |
| * Gets action box area. |
| * @type {!HTMLInputElement} |
| */ |
| @@ -363,8 +371,8 @@ cr.define('login', function() { |
| }, |
| /** |
| - * Gets the custom button. This button is normally hidden, but can be |
| - * shown using the chrome.screenlockPrivate API. |
| + * Gets the custom button. This button is normally hidden, but can be shown |
| + * using the chrome.screenlockPrivate API. |
| * @type {!HTMLInputElement} |
| */ |
| get customButton() { |
| @@ -394,7 +402,12 @@ cr.define('login', function() { |
| }, |
| updateActionBoxArea: function() { |
| - this.actionBoxAreaElement.hidden = this.user_.publicAccount; |
| + if (this.user_.publicAccount || this.user_.isApp) { |
| + this.actionBoxAreaElement.hidden = true; |
| + return; |
| + } |
| + |
| + this.actionBoxAreaElement.hidden = false; |
| this.actionBoxMenuRemoveElement.hidden = !this.user_.canRemove; |
| this.actionBoxAreaElement.setAttribute( |
| @@ -540,8 +553,8 @@ cr.define('login', function() { |
| * Activates the pod. |
| * @return {boolean} True if activated successfully. |
| */ |
| - activate: function() { |
| - if (!this.signinButtonElement.hidden) { |
| + activate: function(e) { |
| + if (this.forceOnlineSignin) { |
| this.showSigninUI(); |
| } else if (!this.passwordElement.value) { |
| return false; |
| @@ -718,7 +731,7 @@ cr.define('login', function() { |
| if (this.parentNode.disabled) |
| return; |
| - if (!this.signinButtonElement.hidden && !this.isActionBoxMenuActive) { |
| + if (this.forceOnlineSignin && !this.isActionBoxMenuActive) { |
| this.showSigninUI(); |
| // Prevent default so that we don't trigger 'focus' event. |
| e.preventDefault(); |
| @@ -867,7 +880,7 @@ cr.define('login', function() { |
| }, |
| /** @override */ |
| - activate: function() { |
| + activate: function(e) { |
| this.expanded = true; |
| this.focusInput(); |
| return true; |
| @@ -885,9 +898,8 @@ cr.define('login', function() { |
| }, |
| /** |
| - * Handle mouse and keyboard events for the learn more button. |
| - * Triggering the button causes information about public sessions to be |
| - * shown. |
| + * Handle mouse and keyboard events for the learn more button. Triggering |
| + * the button causes information about public sessions to be shown. |
| * @param {Event} event Mouse or keyboard event. |
| */ |
| handleLearnMoreEvent: function(event) { |
| @@ -985,7 +997,7 @@ cr.define('login', function() { |
| }, |
| /** @override */ |
| - activate: function() { |
| + activate: function(e) { |
| if (this.passwordElement.hidden) { |
| Oobe.launchUser(this.user.emailAddress, this.user.displayName); |
| } else if (!this.passwordElement.value) { |
| @@ -1011,7 +1023,7 @@ cr.define('login', function() { |
| // If this is an unlocked pod, then open a browser window. Otherwise |
| // just activate the pod and show the password field. |
| if (!this.user.needsSignin && !this.isActionBoxMenuActive) |
| - this.activate(); |
| + this.activate(e); |
| }, |
| /** @override */ |
| @@ -1021,6 +1033,110 @@ cr.define('login', function() { |
| }; |
| /** |
| + * Creates a user pod that represents kiosk app. |
| + * @constructor |
| + * @extends {UserPod} |
| + */ |
| + var AppUserPod = cr.ui.define(function() { |
| + var node = UserPod(); |
| + return node; |
| + }); |
| + |
| + AppUserPod.prototype = { |
| + __proto__: UserPod.prototype, |
| + |
| + /** @override */ |
| + decorate: function() { |
| + UserPod.prototype.decorate.call(this); |
| + this.launchAppButtonElement.addEventListener('click', |
| + this.activate.bind(this)); |
| + }, |
| + |
| + /** @override */ |
| + update: function() { |
| + this.imageElement.src = this.user.iconUrl; |
| + this.imageElement.alt = this.user.label; |
| + this.passwordElement.hidden = true; |
| + this.signinButtonElement.hidden = true; |
| + this.launchAppButtonElement.hidden = false; |
| + this.signedInIndicatorElement.hidden = true; |
| + this.nameElement.textContent = this.user.label; |
| + }, |
| + |
| + /** @override */ |
| + get mainInput() { |
| + return this.launchAppButtonElement; |
| + }, |
| + |
| + /** @override */ |
| + focusInput: function() { |
| + this.signinButtonElement.hidden = true; |
| + this.launchAppButtonElement.hidden = false; |
| + this.passwordElement.hidden = true; |
| + |
| + // Move tabIndex from the whole pod to the main input. |
| + this.tabIndex = -1; |
| + this.mainInput.tabIndex = UserPodTabOrder.POD_INPUT; |
| + this.mainInput.focus(); |
| + }, |
| + |
| + /** @override */ |
| + get forceOnlineSignin() { |
| + return false; |
| + }, |
| + |
| + /** @override */ |
| + activate: function(e) { |
| + var diagnosticMode = e.originalEvent && e.originalEvent.ctrlKey; |
| + this.launchApp_(this.user, diagnosticMode); |
| + return true; |
| + }, |
| + |
| + /** @override */ |
| + handleClickOnPod_: function(e) { |
| + if (this.parentNode.disabled) |
| + return; |
| + |
| + Oobe.clearErrors(); |
| + this.parentNode.lastFocusedPod_ = this; |
| + |
| + // If this is an unlocked pod, then open a browser window. Otherwise |
| + // just activate the pod and show the password field. |
| + if (!this.user.needsSignin && !this.isActionBoxMenuActive) |
| + this.activate(e); |
| + }, |
| + |
| + /** |
| + * Launch the app. If |diagnosticMode| is true, ask user to confirm. |
| + * @param {Object} app App data. |
| + * @param {boolean} diagnosticMode Whether to run the app in diagnostic |
| + * mode. |
| + */ |
| + launchApp_: function(app, diagnosticMode) { |
| + if (!diagnosticMode) { |
| + chrome.send('launchKioskApp', [app.id, false]); |
| + return; |
| + } |
| + |
| + if (!this.confirmDiagnosticMode_) { |
| + this.confirmDiagnosticMode_ = |
| + new cr.ui.dialogs.ConfirmDialog(document.body); |
| + this.confirmDiagnosticMode_.setOkLabel( |
| + loadTimeData.getString('confirmKioskAppDiagnosticModeYes')); |
| + this.confirmDiagnosticMode_.setCancelLabel( |
| + loadTimeData.getString('confirmKioskAppDiagnosticModeNo')); |
| + } |
| + |
| + this.confirmDiagnosticMode_.show( |
| + loadTimeData.getStringF('confirmKioskAppDiagnosticModeFormat', |
| + app.label), |
| + function() { |
| + chrome.send('launchKioskApp', [app.id, true]); |
| + }); |
| + }, |
| + }; |
| + |
| + /** |
| * Creates a new pod row element. |
| * @constructor |
| * @extends {HTMLDivElement} |
| @@ -1048,6 +1164,15 @@ cr.define('login', function() { |
| // Pods whose initial images haven't been loaded yet. |
| podsWithPendingImages_: [], |
| + // Whether pod creation is animated. |
| + user_add_is_animated_: false, |
| + |
| + // Array of apps that are shown in addition to other user pods. |
| + apps_: [], |
| + |
| + // Array of users that are shown (public/supervised/regular). |
| + users_: [], |
| + |
| /** @override */ |
| decorate: function() { |
| // Event listeners that are installed for the time period during which |
| @@ -1080,7 +1205,7 @@ cr.define('login', function() { |
| * Returns pod with the given username (null if there is no such pod). |
| * @param {string} username Username to be matched. |
| * @return {Object} Pod with the given username. null if pod hasn't been |
| - * found. |
| + * found. |
|
xiyuan
2014/02/10 21:15:56
nit: should 4-space indent from @ at previous line
Nikita (slow)
2014/02/12 17:19:25
Done.
|
| */ |
| getPodWithUsername_: function(username) { |
| for (var i = 0, pod; pod = this.pods[i]; ++i) { |
| @@ -1108,7 +1233,7 @@ cr.define('login', function() { |
| /** |
| * Creates a user pod from given email. |
| - * @param {string} email User's email. |
| + * @param {!Object} user User info dictionary. |
| */ |
| createUserPod: function(user) { |
| var userPod; |
| @@ -1116,6 +1241,8 @@ cr.define('login', function() { |
| userPod = new DesktopUserPod({user: user}); |
| else if (user.publicAccount) |
| userPod = new PublicAccountUserPod({user: user}); |
| + else if (user.isApp) |
| + userPod = new AppUserPod({user: user}); |
| else |
| userPod = new UserPod({user: user}); |
| @@ -1202,6 +1329,17 @@ cr.define('login', function() { |
| * @param {boolean} animated Whether to use init animation. |
| */ |
| loadPods: function(users, animated) { |
| + this.users_ = users; |
| + this.user_add_is_animated_ = animated; |
| + |
| + this.rebuildPods(); |
| + }, |
| + |
| + /** |
| + * Rebuilds pod row using users_ and apps_ that were previously set or |
| + * updated. |
| + */ |
| + rebuildPods: function() { |
| // Clear existing pods. |
| this.innerHTML = ''; |
| this.focusedPod_ = undefined; |
| @@ -1212,12 +1350,16 @@ cr.define('login', function() { |
| Oobe.getInstance().toggleClass('flying-pods', false); |
| // Populate the pod row. |
| - for (var i = 0; i < users.length; ++i) { |
| - this.addUserPod(users[i], animated); |
| - } |
| - for (var i = 0, pod; pod = this.pods[i]; ++i) { |
| + for (var i = 0; i < this.users_.length; ++i) |
| + this.addUserPod(this.users_[i], this.user_add_is_animated_); |
| + |
| + for (var i = 0, pod; pod = this.pods[i]; ++i) |
| this.podsWithPendingImages_.push(pod); |
| - } |
| + |
| + // TODO: Edge case handling when kiosk apps are not fitting. |
| + for (var i = 0; i < this.apps_.length; ++i) |
| + this.addUserPod(this.apps_[i], this.user_add_is_animated_); |
| + |
| // Make sure we eventually show the pod row, even if some image is stuck. |
| setTimeout(function() { |
| $('pod-row').classList.remove('images-loading'); |
| @@ -1235,6 +1377,21 @@ cr.define('login', function() { |
| }, |
| /** |
| + * Adds given apps to the pod row. |
| + * @param {array} apps Array of apps. |
| + */ |
| + setApps: function(apps) { |
| + this.apps_ = apps; |
| + this.rebuildPods(); |
| + chrome.send('kioskAppsLoaded'); |
| + |
| + // Check whether there's a pending kiosk app error. |
| + window.setTimeout(function() { |
| + chrome.send('checkKioskAppLaunchError'); |
| + }, 500); |
| + }, |
| + |
| + /** |
| * Shows a button on a user pod with an icon. Clicking on this button |
| * triggers an event used by the chrome.screenlockPrivate API. |
| * @param {string} username Username of pod to add button |
| @@ -1377,7 +1534,7 @@ cr.define('login', function() { |
| * Focuses a given user pod or clear focus when given null. |
| * @param {UserPod=} podToFocus User pod to focus (undefined clears focus). |
| * @param {boolean=} opt_force If true, forces focus update even when |
| - * podToFocus is already focused. |
| + * podToFocus is already focused. |
|
xiyuan
2014/02/10 21:15:56
nit: 4-space indent from @
Nikita (slow)
2014/02/12 17:19:25
Done.
|
| */ |
| focusPod: function(podToFocus, opt_force) { |
| if (this.isFocused(podToFocus) && !opt_force) { |
| @@ -1423,7 +1580,8 @@ cr.define('login', function() { |
| podToFocus.classList.add('focused'); |
| podToFocus.reset(true); // Reset and give focus. |
| // focusPod() automatically loads wallpaper |
| - chrome.send('focusPod', [podToFocus.user.username]); |
| + if (!podToFocus.user.isApp) |
| + chrome.send('focusPod', [podToFocus.user.username]); |
| this.firstShown_ = false; |
| this.lastFocusedPod_ = podToFocus; |
| } |
| @@ -1435,7 +1593,7 @@ cr.define('login', function() { |
| * Focuses a given user pod by index or clear focus when given null. |
| * @param {int=} podToFocus index of User pod to focus. |
| * @param {boolean=} opt_force If true, forces focus update even when |
| - * podToFocus is already focused. |
| + * podToFocus is already focused. |
|
xiyuan
2014/02/10 21:15:56
nit: 4-space indent from @
Nikita (slow)
2014/02/12 17:19:25
Done.
|
| */ |
| focusPodByIndex: function(podToFocus, opt_force) { |
| if (podToFocus < this.pods.length) |