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..a6f05db5a1fd34d23fea99c02d9b2db4c7e6c1fb 100644 |
| --- a/chrome/browser/resources/chromeos/login/user_pod_row.js |
| +++ b/chrome/browser/resources/chromeos/login/user_pod_row.js |
| @@ -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; |
|
xiyuan
2014/02/12 17:35:04
nit: why remove the indent?
Nikita (slow)
2014/02/13 08:58:02
Done.
|
| // (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} |
| */ |
| @@ -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( |
| @@ -538,10 +551,11 @@ cr.define('login', function() { |
| /** |
| * Activates the pod. |
| + * @param {Event} e Event object. |
| * @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 +732,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(); |
| @@ -814,7 +828,7 @@ cr.define('login', function() { |
| this.nameElement.addEventListener('keydown', (function(e) { |
| if (e.keyIdentifier == 'Enter') { |
| - this.parentNode.activatedPod = this; |
| + this.parentNode.setActivatedPod(this, e); |
| // Stop this keydown event from bubbling up to PodRow handler. |
| e.stopPropagation(); |
| // Prevent default so that we don't trigger a 'click' event on the |
| @@ -867,7 +881,7 @@ cr.define('login', function() { |
| }, |
| /** @override */ |
| - activate: function() { |
| + activate: function(e) { |
| this.expanded = true; |
| this.focusInput(); |
| return true; |
| @@ -879,7 +893,7 @@ cr.define('login', function() { |
| return; |
| this.parentNode.focusPod(this); |
| - this.parentNode.activatedPod = this; |
| + this.parentNode.setActivatedPod(this, e); |
| // Prevent default so that we don't trigger 'focus' event. |
| e.preventDefault(); |
| }, |
| @@ -985,7 +999,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 +1025,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 +1035,107 @@ cr.define('login', function() { |
| }; |
| /** |
| + * Creates a user pod that represents kiosk app. |
| + * @constructor |
| + * @extends {UserPod} |
| + */ |
| + var KioskAppPod = cr.ui.define(function() { |
| + var node = UserPod(); |
| + return node; |
| + }); |
| + |
| + KioskAppPod.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 && e.ctrlKey; |
| + this.launchApp_(this.user, diagnosticMode); |
| + return true; |
| + }, |
| + |
| + /** @override */ |
| + handleClickOnPod_: function(e) { |
| + if (this.parentNode.disabled) |
| + return; |
| + |
| + Oobe.clearErrors(); |
| + this.parentNode.lastFocusedPod_ = this; |
| + 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; |
| + } |
| + |
| + var podRow = $('pod-row'); |
| + if (!podRow.confirmDiagnosticMode_) { |
| + podRow.confirmDiagnosticMode_ = |
| + new cr.ui.dialogs.ConfirmDialog(document.body); |
| + podRow.confirmDiagnosticMode_.setOkLabel( |
| + loadTimeData.getString('confirmKioskAppDiagnosticModeYes')); |
| + podRow.confirmDiagnosticMode_.setCancelLabel( |
| + loadTimeData.getString('confirmKioskAppDiagnosticModeNo')); |
| + } |
| + |
| + podRow.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 +1163,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 |
| @@ -1077,10 +1201,24 @@ cr.define('login', function() { |
| }, |
| /** |
| + * Returns pod with the given app id. |
| + * @param {!string} app_id Application id to be matched. |
| + * @return {Object} Pod with the given app id. null if pod hasn't been |
| + * found. |
| + */ |
| + getPodWithAppId_: function(app_id) { |
| + for (var i = 0, pod; pod = this.pods[i]; ++i) { |
| + if (pod.user.isApp && pod.user.id == app_id) |
| + return pod; |
| + } |
| + return null; |
| + }, |
| + |
| + /** |
| * 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. |
| */ |
| getPodWithUsername_: function(username) { |
| for (var i = 0, pod; pod = this.pods[i]; ++i) { |
| @@ -1108,7 +1246,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 +1254,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 KioskAppPod({user: user}); |
| else |
| userPod = new UserPod({user: user}); |
| @@ -1140,6 +1280,30 @@ cr.define('login', function() { |
| }, |
| /** |
| + * Runs app with a given id from the list of loaded apps. |
| + * @param {!string} app_id of an app to run. |
| + * @param {boolean=} opt_diagnostic_mode Whether to run the app in |
| + * diagnostic mode. Default is false. |
| + */ |
| + findAndRunAppForTesting: function(app_id, opt_diagnostic_mode) { |
| + var app = this.getPodWithAppId_(app_id); |
| + if (app) { |
| + var activationEvent = cr.doc.createEvent('Event'); |
| + activationEvent.initEvent('activate', true, true); |
| + |
| + if (opt_diagnostic_mode) { |
| + var fakeCtrlEnterEvent = cr.doc.createEvent('KeyboardEvent'); |
| + fakeCtrlEnterEvent.initKeyboardEvent('keypress', true, true, null, |
| + 'Enter', 0, |
| + true, false, false, false); |
| + activationEvent.originalEvent = fakeCtrlEnterEvent; |
|
xiyuan
2014/02/12 17:35:04
This is different from the expectation at line 109
Nikita (slow)
2014/02/13 08:58:02
Done. Yes, this one plus another JS error.
|
| + } |
| + |
| + app.dispatchEvent(activationEvent); |
| + } |
| + }, |
| + |
| + /** |
| * Removes user pod from pod row. |
| * @param {string} email User's email. |
| */ |
| @@ -1202,6 +1366,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 +1387,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 +1414,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 +1571,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. |
| */ |
| focusPod: function(podToFocus, opt_force) { |
| if (this.isFocused(podToFocus) && !opt_force) { |
| @@ -1423,7 +1617,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 +1630,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. |
| */ |
| focusPodByIndex: function(podToFocus, opt_force) { |
| if (podToFocus < this.pods.length) |
| @@ -1446,7 +1641,7 @@ cr.define('login', function() { |
| * Resets wallpaper to the last active user's wallpaper, if any. |
| */ |
| loadLastWallpaper: function() { |
| - if (this.lastFocusedPod_) |
| + if (this.lastFocusedPod_ && !this.lastFocusedPod_.user.isApp) |
| chrome.send('loadWallpaper', [this.lastFocusedPod_.user.username]); |
| }, |
| @@ -1457,8 +1652,14 @@ cr.define('login', function() { |
| get activatedPod() { |
| return this.activatedPod_; |
| }, |
| - set activatedPod(pod) { |
| - if (pod && pod.activate()) |
| + |
| + /** |
| + * Sets currently activated pod. |
| + * @param {UserPod} pod Pod to check for focus. |
| + * @param {Event} e Event object. |
| + */ |
| + setActivatedPod: function(pod, e) { |
| + if (pod && pod.activate(e)) |
| this.activatedPod_ = pod; |
| }, |
| @@ -1682,7 +1883,7 @@ cr.define('login', function() { |
| break; |
| case 'Enter': |
| if (this.focusedPod_) { |
| - this.activatedPod = this.focusedPod_; |
| + this.setActivatedPod(this.focusedPod_, e); |
| e.stopPropagation(); |
| } |
| break; |
| @@ -1713,7 +1914,8 @@ cr.define('login', function() { |
| focusedPod.reset(true); |
| // Notify screen that it is ready. |
| screen.onShow(); |
| - chrome.send('loadWallpaper', [focusedPod.user.username]); |
| + if (!focusedPod.user.isApp) |
| + chrome.send('loadWallpaper', [focusedPod.user.username]); |
| } |
| }); |
| // Guard timer for 1 second -- it would conver all possible animations. |