Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / login / oobe_screen_user_image.js
blob0628c6a7bbdf1ee5a44524c1a2efc476d82c7fce
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.
5 /**
6  * @fileoverview Oobe user image screen implementation.
7  */
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;
17   return {
18     EXTERNAL_API: [
19       'setDefaultImages',
20       'hideCurtain'
21     ],
23     /** @override */
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.
57           0,                                      // Position.
58           function(el) {
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';
67           });
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');
81           });
82       $('user-image-preview-img').addEventListener(
83           'webkitTransitionEnd', function(e) {
84             previewElement.classList.remove('animation');
85           });
87       var self = this;
88       this.context.addObserver(CONTEXT_KEY_IS_CAMERA_PRESENT,
89                                function(present) {
90         $('user-image-grid').cameraPresent = present;
91       });
92       this.context.addObserver(CONTEXT_KEY_SELECTED_IMAGE_URL,
93                                this.setSelectedImage_);
94       this.context.addObserver(CONTEXT_KEY_PROFILE_PICTURE_DATA_URL,
95                                function(url) {
96         self.profileImageLoading = false;
97         if (url) {
98           self.profileImage_ =
99               $('user-image-grid').updateItem(self.profileImage_, url);
100         }
101       });
103       this.updateLocalizedContent();
105       chrome.send('getImages');
106     },
108     /**
109      * Header text of the screen.
110      * @type {string}
111      */
112     get header() {
113       return loadTimeData.getString('userImageScreenTitle');
114     },
116     /**
117      * Buttons in oobe wizard's button strip.
118      * @type {array} Array of Buttons.
119      */
120     get 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));
125       return [okButton];
126     },
128     /**
129      * The caption to use for the Profile image preview.
130      * @type {string}
131      */
132     get profileImageCaption() {
133       return this.profileImageCaption_;
134     },
135     set profileImageCaption(value) {
136       this.profileImageCaption_ = value;
137       this.updateCaption_();
138     },
140     /**
141      * True if the Profile image is being loaded.
142      * @type {boolean}
143      */
144     get profileImageLoading() {
145       return this.profileImageLoading_;
146     },
147     set profileImageLoading(value) {
148       this.profileImageLoading_ = value;
149       $('user-image-screen-main').classList.toggle('profile-image-loading',
150                                                    value);
151       if (value)
152         announceAccessibleMessage(loadTimeData.getString('syncingPreferences'));
153       this.updateProfileImageCaption_();
154     },
156     /**
157      * Handles image activation (by pressing Enter).
158      * @private
159      */
160     handleImageActivated_: function() {
161       switch ($('user-image-grid').selectedItemUrl) {
162         case ButtonImages.TAKE_PHOTO:
163           this.handleTakePhoto_();
164           break;
165         default:
166           this.acceptImage_();
167           break;
168       }
169     },
171     /**
172      * Handles selection change.
173      * @param {Event} e Selection change event.
174      * @private
175      */
176     handleSelect_: function(e) {
177       var imageGrid = $('user-image-grid');
178       $('ok-button').disabled = false;
180       // Camera selection
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;
187         } else {
188           imageGrid.previewElement.classList.add('phototaken');
189           this.notifyImageSelected_();
190         }
191       } else {
192         imageGrid.previewElement.classList.remove('phototaken');
193         $('flip-photo').tabIndex = -1;
194         this.notifyImageSelected_();
195       }
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(
203               function() {
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;
208               });
209         } else {
210           $('user-image-preview-img').classList.toggle('animated-transform',
211                                                        false);
212           imageGrid.stopCamera();
213         }
214       }
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';
223     },
225     /**
226      * Handle camera-photo flip.
227      */
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));
235     },
237     /**
238      * Handle photo capture from the live camera stream.
239      */
240     handleTakePhoto_: function(e) {
241       $('user-image-grid').takePhoto();
242       chrome.send('takePhoto');
243     },
245     /**
246      * Handle photo captured event.
247      * @param {Event} e Event with 'dataURL' property containing a data URL.
248      */
249     handlePhotoTaken_: function(e) {
250       chrome.send('photoTaken', [e.dataURL]);
251       announceAccessibleMessage(
252           loadTimeData.getString('photoCaptureAccessibleText'));
253     },
255     /**
256      * Handle photo updated event.
257      * @param {Event} e Event with 'dataURL' property containing a data URL.
258      */
259     handlePhotoUpdated_: function(e) {
260       chrome.send('photoTaken', [e.dataURL]);
261     },
263     /**
264      * Handle discarding the captured photo.
265      */
266     handleDiscardPhoto_: function(e) {
267       var imageGrid = $('user-image-grid');
268       imageGrid.discardPhoto();
269       chrome.send('discardPhoto');
270       announceAccessibleMessage(
271           loadTimeData.getString('photoDiscardAccessibleText'));
272     },
274     /**
275      * Event handler that is invoked just before the screen is shown.
276      * @param {object} data Screen init payload.
277      */
278     onBeforeShow: function(data) {
279       Oobe.getInstance().headerHidden = true;
280       this.loading = true;
281       var imageGrid = $('user-image-grid');
282       imageGrid.updateAndFocus();
283       chrome.send('onUserImageScreenShown');
284     },
286     /**
287      * Event handler that is invoked just before the screen is hidden.
288      */
289     onBeforeHide: function() {
290       $('user-image-grid').stopCamera();
291       this.loading = false;
292     },
294     /**
295      * Accepts currently selected image, if possible.
296      * @private
297      */
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');
305         this.loading = true;
306       }
307     },
309     /**
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.
313      */
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');
319     },
321     /**
322      * Selects user image with the given URL.
323      * @param {string} url URL of the image to select.
324      * @private
325      */
326     setSelectedImage_: function(url) {
327       if (!url)
328         return;
329       var imageGrid = $('user-image-grid');
330       imageGrid.selectedItemUrl = url;
331       imageGrid.focus();
332     },
334     get loading() {
335       return this.classList.contains('loading');
336     },
338     set loading(value) {
339       this.classList.toggle('loading', value);
340       $('oobe').classList.toggle('image-loading', value);
341       Oobe.getInstance().updateScreenSize(this);
342     },
344     /**
345      * Hides curtain with spinner.
346      */
347     hideCurtain: function() {
348       this.loading = false;
349     },
351     /**
352      * Updates the image preview caption.
353      * @private
354      */
355     updateCaption_: function() {
356       $('user-image-preview-caption').textContent =
357           $('user-image-grid').selectionType == 'profile' ?
358           this.profileImageCaption : '';
359     },
361     /**
362      * Updates localized content of the screen that is not updated via template.
363      */
364     updateLocalizedContent: function() {
365       this.updateProfileImageCaption_();
366     },
368     /**
369      * Updates profile image caption.
370      * @private
371      */
372     updateProfileImageCaption_: function() {
373       this.profileImageCaption = loadTimeData.getString(
374         this.profileImageLoading_ ? 'profilePhotoLoading' : 'profilePhoto');
375     },
377     /**
378      * Notifies chrome about image selection.
379      * @private
380      */
381     notifyImageSelected_: function() {
382       var imageGrid = $('user-image-grid');
383       chrome.send('selectImage',
384                   [imageGrid.selectedItemUrl,
385                    imageGrid.selectionType,
386                    !imageGrid.inProgramSelection]);
387     }
388   };