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 login.createScreen('UserImageScreen', 'user-image', function() {
10 var CONTEXT_KEY_IS_CAMERA_PRESENT = 'isCameraPresent';
11 var CONTEXT_KEY_SELECTED_IMAGE_URL = 'selectedImageURL';
12 var CONTEXT_KEY_PROFILE_PICTURE_DATA_URL = 'profilePictureDataURL';
14 var UserImagesGrid = options.UserImagesGrid;
15 var ButtonImages = UserImagesGrid.ButtonImages;
24 decorate: function(element) {
25 var imageGrid = $('user-image-grid');
26 UserImagesGrid.decorate(imageGrid);
28 // Preview image will track the selected item's URL.
29 var previewElement = $('user-image-preview');
30 previewElement.oncontextmenu = function(e) { e.preventDefault(); };
32 imageGrid.previewElement = previewElement;
33 imageGrid.selectionType = 'default';
34 imageGrid.flipPhotoElement = $('flip-photo');
36 imageGrid.addEventListener('select',
37 this.handleSelect_.bind(this));
38 imageGrid.addEventListener('activate',
39 this.handleImageActivated_.bind(this));
40 imageGrid.addEventListener('phototaken',
41 this.handlePhotoTaken_.bind(this));
42 imageGrid.addEventListener('photoupdated',
43 this.handlePhotoUpdated_.bind(this));
45 // Set the title for camera item in the grid.
46 imageGrid.setCameraTitles(
47 loadTimeData.getString('takePhoto'),
48 loadTimeData.getString('photoFromCamera'));
50 this.profileImageLoading = true;
52 // Profile image data (if present).
53 this.profileImage_ = imageGrid.addItem(
54 ButtonImages.PROFILE_PICTURE, // Image URL.
55 loadTimeData.getString('profilePhoto'), // Title.
56 undefined, // Click handler.
59 // Custom decorator for Profile image element.
60 var spinner = el.ownerDocument.createElement('div');
61 spinner.className = 'spinner';
62 var spinnerBg = el.ownerDocument.createElement('div');
63 spinnerBg.className = 'spinner-bg';
64 spinnerBg.appendChild(spinner);
65 el.appendChild(spinnerBg);
66 el.id = 'profile-image';
68 this.profileImage_.type = 'profile';
70 $('take-photo').addEventListener(
71 'click', this.handleTakePhoto_.bind(this));
72 $('discard-photo').addEventListener(
73 'click', this.handleDiscardPhoto_.bind(this));
75 // Toggle 'animation' class for the duration of WebKit transition.
76 $('flip-photo').addEventListener(
77 'click', this.handleFlipPhoto_.bind(this));
78 $('user-image-stream-crop').addEventListener(
79 'webkitTransitionEnd', function(e) {
80 previewElement.classList.remove('animation');
82 $('user-image-preview-img').addEventListener(
83 'webkitTransitionEnd', function(e) {
84 previewElement.classList.remove('animation');
88 this.context.addObserver(CONTEXT_KEY_IS_CAMERA_PRESENT,
90 $('user-image-grid').cameraPresent = present;
92 this.context.addObserver(CONTEXT_KEY_SELECTED_IMAGE_URL,
93 this.setSelectedImage_);
94 this.context.addObserver(CONTEXT_KEY_PROFILE_PICTURE_DATA_URL,
96 self.profileImageLoading = false;
99 $('user-image-grid').updateItem(self.profileImage_, url);
103 this.updateLocalizedContent();
105 chrome.send('getImages');
109 * Header text of the screen.
113 return loadTimeData.getString('userImageScreenTitle');
117 * Buttons in oobe wizard's button strip.
118 * @type {array} Array of Buttons.
121 var okButton = this.ownerDocument.createElement('button');
122 okButton.id = 'ok-button';
123 okButton.textContent = loadTimeData.getString('okButtonText');
124 okButton.addEventListener('click', this.acceptImage_.bind(this));
129 * The caption to use for the Profile image preview.
132 get profileImageCaption() {
133 return this.profileImageCaption_;
135 set profileImageCaption(value) {
136 this.profileImageCaption_ = value;
137 this.updateCaption_();
141 * True if the Profile image is being loaded.
144 get profileImageLoading() {
145 return this.profileImageLoading_;
147 set profileImageLoading(value) {
148 this.profileImageLoading_ = value;
149 $('user-image-screen-main').classList.toggle('profile-image-loading',
152 announceAccessibleMessage(loadTimeData.getString('syncingPreferences'));
153 this.updateProfileImageCaption_();
157 * Handles image activation (by pressing Enter).
160 handleImageActivated_: function() {
161 switch ($('user-image-grid').selectedItemUrl) {
162 case ButtonImages.TAKE_PHOTO:
163 this.handleTakePhoto_();
172 * Handles selection change.
173 * @param {Event} e Selection change event.
176 handleSelect_: function(e) {
177 var imageGrid = $('user-image-grid');
178 $('ok-button').disabled = false;
181 if (imageGrid.selectionType == 'camera') {
182 $('flip-photo').tabIndex = 1;
183 // No current image selected.
184 if (imageGrid.cameraLive) {
185 imageGrid.previewElement.classList.remove('phototaken');
186 $('ok-button').disabled = true;
188 imageGrid.previewElement.classList.add('phototaken');
189 this.notifyImageSelected_();
192 imageGrid.previewElement.classList.remove('phototaken');
193 $('flip-photo').tabIndex = -1;
194 this.notifyImageSelected_();
196 // Start/stop camera on (de)selection.
197 if (!imageGrid.inProgramSelection &&
198 imageGrid.selectionType != e.oldSelectionType) {
199 if (imageGrid.selectionType == 'camera') {
200 // Programmatic selection of camera item is done in
201 // startCamera callback where streaming is started by itself.
202 imageGrid.startCamera(
204 // Start capture if camera is still the selected item.
205 $('user-image-preview-img').classList.toggle(
206 'animated-transform', true);
207 return imageGrid.selectedItem == imageGrid.cameraImage;
210 $('user-image-preview-img').classList.toggle('animated-transform',
212 imageGrid.stopCamera();
215 this.updateCaption_();
216 // Update image attribution text.
217 var image = imageGrid.selectedItem;
218 $('user-image-author-name').textContent = image.author;
219 $('user-image-author-website').textContent = image.website;
220 $('user-image-author-website').href = image.website;
221 $('user-image-attribution').style.visibility =
222 (image.author || image.website) ? 'visible' : 'hidden';
226 * Handle camera-photo flip.
228 handleFlipPhoto_: function() {
229 var imageGrid = $('user-image-grid');
230 imageGrid.previewElement.classList.add('animation');
231 imageGrid.flipPhoto = !imageGrid.flipPhoto;
232 var flipMessageId = imageGrid.flipPhoto ?
233 'photoFlippedAccessibleText' : 'photoFlippedBackAccessibleText';
234 announceAccessibleMessage(loadTimeData.getString(flipMessageId));
238 * Handle photo capture from the live camera stream.
240 handleTakePhoto_: function(e) {
241 $('user-image-grid').takePhoto();
242 chrome.send('takePhoto');
246 * Handle photo captured event.
247 * @param {Event} e Event with 'dataURL' property containing a data URL.
249 handlePhotoTaken_: function(e) {
250 chrome.send('photoTaken', [e.dataURL]);
251 announceAccessibleMessage(
252 loadTimeData.getString('photoCaptureAccessibleText'));
256 * Handle photo updated event.
257 * @param {Event} e Event with 'dataURL' property containing a data URL.
259 handlePhotoUpdated_: function(e) {
260 chrome.send('photoTaken', [e.dataURL]);
264 * Handle discarding the captured photo.
266 handleDiscardPhoto_: function(e) {
267 var imageGrid = $('user-image-grid');
268 imageGrid.discardPhoto();
269 chrome.send('discardPhoto');
270 announceAccessibleMessage(
271 loadTimeData.getString('photoDiscardAccessibleText'));
275 * Event handler that is invoked just before the screen is shown.
276 * @param {object} data Screen init payload.
278 onBeforeShow: function(data) {
279 Oobe.getInstance().headerHidden = true;
281 var imageGrid = $('user-image-grid');
282 imageGrid.updateAndFocus();
283 chrome.send('onUserImageScreenShown');
287 * Event handler that is invoked just before the screen is hidden.
289 onBeforeHide: function() {
290 $('user-image-grid').stopCamera();
291 this.loading = false;
295 * Accepts currently selected image, if possible.
298 acceptImage_: function() {
299 var okButton = $('ok-button');
300 if (!okButton.disabled) {
301 // This ensures that #ok-button won't be re-enabled again.
302 $('user-image-grid').disabled = true;
303 okButton.disabled = true;
304 chrome.send('onUserImageAccepted');
310 * Appends default images to the image grid. Should only be called once.
311 * @param {Array<{url: string, author: string, website: string}>} images
312 * An array of default images data, including URL, author and website.
314 setDefaultImages: function(imagesData) {
315 $('user-image-grid').setDefaultImages(imagesData);
316 this.setSelectedImage_(
317 this.context.get(CONTEXT_KEY_SELECTED_IMAGE_URL, ''));
318 chrome.send('screenReady');
322 * Selects user image with the given URL.
323 * @param {string} url URL of the image to select.
326 setSelectedImage_: function(url) {
329 var imageGrid = $('user-image-grid');
330 imageGrid.selectedItemUrl = url;
335 return this.classList.contains('loading');
339 this.classList.toggle('loading', value);
340 $('oobe').classList.toggle('image-loading', value);
341 Oobe.getInstance().updateScreenSize(this);
345 * Hides curtain with spinner.
347 hideCurtain: function() {
348 this.loading = false;
352 * Updates the image preview caption.
355 updateCaption_: function() {
356 $('user-image-preview-caption').textContent =
357 $('user-image-grid').selectionType == 'profile' ?
358 this.profileImageCaption : '';
362 * Updates localized content of the screen that is not updated via template.
364 updateLocalizedContent: function() {
365 this.updateProfileImageCaption_();
369 * Updates profile image caption.
372 updateProfileImageCaption_: function() {
373 this.profileImageCaption = loadTimeData.getString(
374 this.profileImageLoading_ ? 'profilePhotoLoading' : 'profilePhoto');
378 * Notifies chrome about image selection.
381 notifyImageSelected_: function() {
382 var imageGrid = $('user-image-grid');
383 chrome.send('selectImage',
384 [imageGrid.selectedItemUrl,
385 imageGrid.selectionType,
386 !imageGrid.inProgramSelection]);