| 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..d3918ac3897f98efb460b24ffc8dfedf0c87ea24 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() {
|
| @@ -390,11 +398,16 @@ cr.define('login', function() {
|
| this.passwordElement.setAttribute('aria-label', loadTimeData.getStringF(
|
| 'passwordFieldAccessibleName', this.user_.emailAddress));
|
|
|
| - this.updateUserTypeIcon();
|
| + this.customizeUserPodPerUserType();
|
| },
|
|
|
| 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(
|
| @@ -414,28 +427,33 @@ cr.define('login', function() {
|
| loadTimeData.getString('removeUser');
|
| },
|
|
|
| - updateUserTypeIcon: function() {
|
| + customizeUserPodPerUserType: function() {
|
| var isMultiProfilesUI =
|
| (Oobe.getInstance().displayType == DISPLAY_TYPE.USER_ADDING);
|
|
|
| if (this.user_.locallyManagedUser) {
|
| - this.userTypeIconAreaElement.classList.add('supervised');
|
| - this.userTypeIconAreaElement.hidden = false;
|
| + this.setUserPodIconType('supervised');
|
| } else if (isMultiProfilesUI && !this.user_.isMultiProfilesAllowed) {
|
| - // Mark user pod as not focusable.
|
| + // Mark user pod as not focusable which in addition to the grayed out
|
| + // filter makes it look in disabled state.
|
| this.classList.add('not-focusable');
|
| -
|
| - this.userTypeIconAreaElement.classList.add('policy');
|
| - this.userTypeIconAreaElement.hidden = false;
|
| + this.setUserPodIconType('policy');
|
|
|
| this.querySelector('.mp-policy-title').hidden = false;
|
| - if (this.user_.multiProfilesPolicy == 'primary-only')
|
| + if (this.user.multiProfilesPolicy == 'primary-only')
|
| this.querySelector('.mp-policy-primary-only-msg').hidden = false;
|
| else
|
| this.querySelector('.mp-policy-not-allowed-msg').hidden = false;
|
| + } else if (this.user_.isApp) {
|
| + this.setUserPodIconType('app');
|
| }
|
| },
|
|
|
| + setUserPodIconType: function(userTypeClass) {
|
| + this.userTypeIconAreaElement.classList.add(userTypeClass);
|
| + this.userTypeIconAreaElement.hidden = false;
|
| + },
|
| +
|
| /**
|
| * The user that this pod represents.
|
| * @type {!Object}
|
| @@ -538,10 +556,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 +737,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 +833,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 +886,7 @@ cr.define('login', function() {
|
| },
|
|
|
| /** @override */
|
| - activate: function() {
|
| + activate: function(e) {
|
| this.expanded = true;
|
| this.focusInput();
|
| return true;
|
| @@ -879,15 +898,14 @@ 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();
|
| },
|
|
|
| /**
|
| - * 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 +1003,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 +1029,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 +1039,110 @@ 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;
|
| +
|
| + UserPod.prototype.updateActionBoxArea.call(this);
|
| + UserPod.prototype.customizeUserPodPerUserType.call(this);
|
| + },
|
| +
|
| + /** @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 oobe = $('oobe');
|
| + if (!oobe.confirmDiagnosticMode_) {
|
| + oobe.confirmDiagnosticMode_ =
|
| + new cr.ui.dialogs.ConfirmDialog(document.body);
|
| + oobe.confirmDiagnosticMode_.setOkLabel(
|
| + loadTimeData.getString('confirmKioskAppDiagnosticModeYes'));
|
| + oobe.confirmDiagnosticMode_.setCancelLabel(
|
| + loadTimeData.getString('confirmKioskAppDiagnosticModeNo'));
|
| + }
|
| +
|
| + oobe.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 +1170,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 +1208,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 +1253,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 +1261,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 +1287,23 @@ 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('MouseEvents');
|
| + var ctrlKey = opt_diagnostic_mode;
|
| + activationEvent.initMouseEvent('click', true, true, null,
|
| + 0, 0, 0, 0, 0, ctrlKey, false, false, false, 0, null);
|
| + 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.
|
|
|