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;
280 $('oobe').classList
.add('image-loading');
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 $('oobe').classList
.remove('image-loading');
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');
309 * Appends default images to the image grid. Should only be called once.
310 * @param {Array<{url: string, author: string, website: string}>} images
311 * An array of default images data, including URL, author and website.
313 setDefaultImages: function(imagesData
) {
314 $('user-image-grid').setDefaultImages(imagesData
);
315 this.setSelectedImage_(
316 this.context
.get(CONTEXT_KEY_SELECTED_IMAGE_URL
, ''));
317 chrome
.send('screenReady');
321 * Selects user image with the given URL.
322 * @param {string} url URL of the image to select.
325 setSelectedImage_: function(url
) {
328 var imageGrid
= $('user-image-grid');
329 imageGrid
.selectedItemUrl
= url
;
334 * Hides curtain with spinner.
336 hideCurtain: function() {
337 this.classList
.remove('loading');
338 $('oobe').classList
.remove('image-loading');
339 Oobe
.getInstance().updateScreenSize(this);
343 * Updates the image preview caption.
346 updateCaption_: function() {
347 $('user-image-preview-caption').textContent
=
348 $('user-image-grid').selectionType
== 'profile' ?
349 this.profileImageCaption
: '';
353 * Updates localized content of the screen that is not updated via template.
355 updateLocalizedContent: function() {
356 this.updateProfileImageCaption_();
360 * Updates profile image caption.
363 updateProfileImageCaption_: function() {
364 this.profileImageCaption
= loadTimeData
.getString(
365 this.profileImageLoading_
? 'profilePhotoLoading' : 'profilePhoto');
369 * Notifies chrome about image selection.
372 notifyImageSelected_: function() {
373 var imageGrid
= $('user-image-grid');
374 chrome
.send('selectImage',
375 [imageGrid
.selectedItemUrl
,
376 imageGrid
.selectionType
,
377 !imageGrid
.inProgramSelection
]);