1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview Oobe user image screen implementation.
9 cr.define('login', function() {
10 var UserImagesGrid = options.UserImagesGrid;
11 var ButtonImages = UserImagesGrid.ButtonImages;
14 * Array of button URLs used on this page.
15 * @type {Array.<string>}
18 var ButtonImageUrls = [
19 ButtonImages.TAKE_PHOTO
23 * Whether the web camera item should be preselected, if available.
27 var PRESELECT_CAMERA = false;
30 * Creates a new OOBE screen div.
32 * @extends {HTMLDivElement}
34 var UserImageScreen = cr.ui.define(login.Screen);
37 * Registers with Oobe.
38 * @param {boolean} lazyInit If true, screen is decorated on first show.
40 UserImageScreen.register = function(lazyInit) {
41 var screen = $('user-image');
43 screen.__proto__ = UserImageScreen.prototype;
44 screen.deferredDecorate = function() {
45 UserImageScreen.decorate(screen);
48 UserImageScreen.decorate(screen);
50 Oobe.getInstance().registerScreen(screen);
53 UserImageScreen.prototype = {
54 __proto__: login.Screen.prototype,
57 * Currently selected user image index (take photo button is with zero
61 selectedUserImage_: -1,
64 * URL for profile picture.
66 profileImageUrl_: null,
69 decorate: function(element) {
70 var imageGrid = $('user-image-grid');
71 UserImagesGrid.decorate(imageGrid);
73 // Preview image will track the selected item's URL.
74 var previewElement = $('user-image-preview');
75 previewElement.oncontextmenu = function(e) { e.preventDefault(); };
77 imageGrid.previewElement = previewElement;
78 imageGrid.selectionType = 'default';
79 imageGrid.flipPhotoElement = $('flip-photo');
81 imageGrid.addEventListener('select',
82 this.handleSelect_.bind(this));
83 imageGrid.addEventListener('activate',
84 this.handleImageActivated_.bind(this));
85 imageGrid.addEventListener('phototaken',
86 this.handlePhotoTaken_.bind(this));
87 imageGrid.addEventListener('photoupdated',
88 this.handlePhotoUpdated_.bind(this));
90 // Set the title for camera item in the grid.
91 imageGrid.setCameraTitles(
92 loadTimeData.getString('takePhoto'),
93 loadTimeData.getString('photoFromCamera'));
95 this.profileImageLoading = true;
97 // Profile image data (if present).
98 this.profileImage_ = imageGrid.addItem(
99 ButtonImages.PROFILE_PICTURE, // Image URL.
100 loadTimeData.getString('profilePhoto'), // Title.
101 undefined, // Click handler.
104 // Custom decorator for Profile image element.
105 var spinner = el.ownerDocument.createElement('div');
106 spinner.className = 'spinner';
107 var spinnerBg = el.ownerDocument.createElement('div');
108 spinnerBg.className = 'spinner-bg';
109 spinnerBg.appendChild(spinner);
110 el.appendChild(spinnerBg);
111 el.id = 'profile-image';
113 this.profileImage_.type = 'profile';
115 $('take-photo').addEventListener(
116 'click', this.handleTakePhoto_.bind(this));
117 $('discard-photo').addEventListener(
118 'click', this.handleDiscardPhoto_.bind(this));
120 // Toggle 'animation' class for the duration of WebKit transition.
121 $('flip-photo').addEventListener(
122 'click', this.handleFlipPhoto_.bind(this));
123 $('user-image-stream-crop').addEventListener(
124 'webkitTransitionEnd', function(e) {
125 previewElement.classList.remove('animation');
127 $('user-image-preview-img').addEventListener(
128 'webkitTransitionEnd', function(e) {
129 previewElement.classList.remove('animation');
132 this.updateLocalizedContent();
134 chrome.send('getImages');
138 * Header text of the screen.
142 return loadTimeData.getString('userImageScreenTitle');
146 * Buttons in oobe wizard's button strip.
147 * @type {array} Array of Buttons.
150 var okButton = this.ownerDocument.createElement('button');
151 okButton.id = 'ok-button';
152 okButton.textContent = loadTimeData.getString('okButtonText');
153 okButton.addEventListener('click', this.acceptImage_.bind(this));
158 * The caption to use for the Profile image preview.
161 get profileImageCaption() {
162 return this.profileImageCaption_;
164 set profileImageCaption(value) {
165 this.profileImageCaption_ = value;
166 this.updateCaption_();
170 * True if the Profile image is being loaded.
173 get profileImageLoading() {
174 return this.profileImageLoading_;
176 set profileImageLoading(value) {
177 this.profileImageLoading_ = value;
178 $('user-image-screen-main').classList.toggle('profile-image-loading',
181 announceAccessibleMessage(loadTimeData.getString('syncingPreferences'));
182 this.updateProfileImageCaption_();
186 * Handles image activation (by pressing Enter).
189 handleImageActivated_: function() {
190 switch ($('user-image-grid').selectedItemUrl) {
191 case ButtonImages.TAKE_PHOTO:
192 this.handleTakePhoto_();
201 * Handles selection change.
202 * @param {Event} e Selection change event.
205 handleSelect_: function(e) {
206 var imageGrid = $('user-image-grid');
207 $('ok-button').disabled = false;
210 if (imageGrid.selectionType == 'camera') {
211 $('flip-photo').tabIndex = 1;
212 // No current image selected.
213 if (imageGrid.cameraLive) {
214 imageGrid.previewElement.classList.remove('phototaken');
215 $('ok-button').disabled = true;
217 imageGrid.previewElement.classList.add('phototaken');
218 this.notifyImageSelected_();
221 imageGrid.previewElement.classList.remove('phototaken');
222 $('flip-photo').tabIndex = -1;
223 this.notifyImageSelected_();
225 // Start/stop camera on (de)selection.
226 if (!imageGrid.inProgramSelection &&
227 imageGrid.selectionType != e.oldSelectionType) {
228 if (imageGrid.selectionType == 'camera') {
229 // Programmatic selection of camera item is done in
230 // startCamera callback where streaming is started by itself.
231 imageGrid.startCamera(
233 // Start capture if camera is still the selected item.
234 $('user-image-preview-img').classList.toggle(
235 'animated-transform', true);
236 return imageGrid.selectedItem == imageGrid.cameraImage;
239 $('user-image-preview-img').classList.toggle('animated-transform',
241 imageGrid.stopCamera();
244 this.updateCaption_();
245 // Update image attribution text.
246 var image = imageGrid.selectedItem;
247 $('user-image-author-name').textContent = image.author;
248 $('user-image-author-website').textContent = image.website;
249 $('user-image-author-website').href = image.website;
250 $('user-image-attribution').style.visibility =
251 (image.author || image.website) ? 'visible' : 'hidden';
255 * Handle camera-photo flip.
257 handleFlipPhoto_: function() {
258 var imageGrid = $('user-image-grid');
259 imageGrid.previewElement.classList.add('animation');
260 imageGrid.flipPhoto = !imageGrid.flipPhoto;
261 var flipMessageId = imageGrid.flipPhoto ?
262 'photoFlippedAccessibleText' : 'photoFlippedBackAccessibleText';
263 announceAccessibleMessage(loadTimeData.getString(flipMessageId));
267 * Handle photo capture from the live camera stream.
269 handleTakePhoto_: function(e) {
270 $('user-image-grid').takePhoto();
271 chrome.send('takePhoto');
275 * Handle photo captured event.
276 * @param {Event} e Event with 'dataURL' property containing a data URL.
278 handlePhotoTaken_: function(e) {
279 chrome.send('photoTaken', [e.dataURL]);
280 announceAccessibleMessage(
281 loadTimeData.getString('photoCaptureAccessibleText'));
285 * Handle photo updated event.
286 * @param {Event} e Event with 'dataURL' property containing a data URL.
288 handlePhotoUpdated_: function(e) {
289 chrome.send('photoTaken', [e.dataURL]);
293 * Handle discarding the captured photo.
295 handleDiscardPhoto_: function(e) {
296 var imageGrid = $('user-image-grid');
297 imageGrid.discardPhoto();
298 chrome.send('discardPhoto');
299 announceAccessibleMessage(
300 loadTimeData.getString('photoDiscardAccessibleText'));
304 * Event handler that is invoked just before the screen is shown.
305 * @param {object} data Screen init payload.
307 onBeforeShow: function(data) {
308 Oobe.getInstance().headerHidden = true;
309 var imageGrid = $('user-image-grid');
310 imageGrid.updateAndFocus();
311 chrome.send('onUserImageScreenShown');
315 * Event handler that is invoked just before the screen is hidden.
317 onBeforeHide: function() {
318 $('user-image-grid').stopCamera();
322 * Accepts currently selected image, if possible.
325 acceptImage_: function() {
326 var okButton = $('ok-button');
327 if (!okButton.disabled) {
328 // This ensures that #ok-button won't be re-enabled again.
329 $('user-image-grid').disabled = true;
330 okButton.disabled = true;
331 chrome.send('onUserImageAccepted');
336 * Updates user profile image.
337 * @param {?string} imageUrl Image encoded as data URL. If null, user has
338 * the default profile image, which we don't want to show.
341 setProfileImage_: function(imageUrl) {
342 this.profileImageLoading = false;
343 this.profileImageUrl_ = imageUrl;
344 if (imageUrl !== null) {
346 $('user-image-grid').updateItem(this.profileImage_, imageUrl);
351 * @param {boolean} present Whether camera is detected.
353 setCameraPresent_: function(present) {
354 $('user-image-grid').cameraPresent = present;
358 * Controls the profile image as one of image options.
359 * @param {enabled} Whether profile image option should be displayed.
362 setProfilePictureEnabled_: function(enabled) {
363 var imageGrid = $('user-image-grid');
366 imageGrid.removeItem(this.profileImage_);
371 * Appends default images to the image grid. Should only be called once.
372 * @param {Array.<{url: string, author: string, website: string}>} images
373 * An array of default images data, including URL, author and website.
376 setDefaultImages_: function(imagesData) {
377 var imageGrid = $('user-image-grid');
378 for (var i = 0, data; data = imagesData[i]; i++) {
379 var item = imageGrid.addItem(data.url, data.title);
380 item.type = 'default';
381 item.author = data.author || '';
382 item.website = data.website || '';
384 chrome.send('screenReady');
388 * Selects user image with the given URL.
389 * @param {string} url URL of the image to select.
392 setSelectedImage_: function(url) {
393 var imageGrid = $('user-image-grid');
394 imageGrid.selectedItemUrl = url;
399 * Hides curtain with spinner.
402 hideCurtain_: function() {
403 this.classList.remove('loading');
404 Oobe.getInstance().updateScreenSize(this);
408 * Updates the image preview caption.
411 updateCaption_: function() {
412 $('user-image-preview-caption').textContent =
413 $('user-image-grid').selectionType == 'profile' ?
414 this.profileImageCaption : '';
418 * Updates localized content of the screen that is not updated via template.
420 updateLocalizedContent: function() {
421 this.updateProfileImageCaption_();
425 * Updates profile image caption.
428 updateProfileImageCaption_: function() {
429 this.profileImageCaption = loadTimeData.getString(
430 this.profileImageLoading_ ? 'profilePhotoLoading' : 'profilePhoto');
434 * Notifies chrome about image selection.
437 notifyImageSelected_: function() {
438 var imageGrid = $('user-image-grid');
439 chrome.send('selectImage',
440 [imageGrid.selectedItemUrl,
441 imageGrid.selectionType,
442 !imageGrid.inProgramSelection]);
446 // Forward public APIs to private implementations.
447 cr.makePublic(UserImageScreen, [
450 'setProfilePictureEnabled',
457 UserImageScreen: UserImageScreen