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. 4 5cr.define('options', function() { 6 var Page = cr.ui.pageManager.Page; 7 var PageManager = cr.ui.pageManager.PageManager; 8 var UserImagesGrid = options.UserImagesGrid; 9 var ButtonImages = UserImagesGrid.ButtonImages; 10 11 /** 12 * Array of button URLs used on this page. 13 * @type {Array.<string>} 14 * @const 15 */ 16 var ButtonImageUrls = [ 17 ButtonImages.TAKE_PHOTO, 18 ButtonImages.CHOOSE_FILE 19 ]; 20 21 ///////////////////////////////////////////////////////////////////////////// 22 // ChangePictureOptions class: 23 24 /** 25 * Encapsulated handling of ChromeOS change picture options page. 26 * @constructor 27 * @extends {cr.ui.pageManager.Page} 28 */ 29 function ChangePictureOptions() { 30 Page.call(this, 'changePicture', 31 loadTimeData.getString('changePicturePage'), 32 'change-picture-page'); 33 } 34 35 cr.addSingletonGetter(ChangePictureOptions); 36 37 ChangePictureOptions.prototype = { 38 // Inherit ChangePictureOptions from Page. 39 __proto__: Page.prototype, 40 41 /** @override */ 42 initializePage: function() { 43 Page.prototype.initializePage.call(this); 44 45 var imageGrid = $('user-image-grid'); 46 UserImagesGrid.decorate(imageGrid); 47 48 // Preview image will track the selected item's URL. 49 var previewElement = $('user-image-preview'); 50 previewElement.oncontextmenu = function(e) { e.preventDefault(); }; 51 52 imageGrid.previewElement = previewElement; 53 imageGrid.selectionType = 'default'; 54 imageGrid.flipPhotoElement = $('flip-photo'); 55 56 imageGrid.addEventListener('select', 57 this.handleImageSelected_.bind(this)); 58 imageGrid.addEventListener('activate', 59 this.handleImageActivated_.bind(this)); 60 imageGrid.addEventListener('phototaken', 61 this.handlePhotoTaken_.bind(this)); 62 imageGrid.addEventListener('photoupdated', 63 this.handlePhotoTaken_.bind(this)); 64 65 // Add the "Choose file" button. 66 imageGrid.addItem(ButtonImages.CHOOSE_FILE, 67 loadTimeData.getString('chooseFile'), 68 this.handleChooseFile_.bind(this)).type = 'file'; 69 70 // Profile image data. 71 this.profileImage_ = imageGrid.addItem( 72 ButtonImages.PROFILE_PICTURE, 73 loadTimeData.getString('profilePhotoLoading')); 74 this.profileImage_.type = 'profile'; 75 76 // Set the title for camera item in the grid. 77 imageGrid.setCameraTitles( 78 loadTimeData.getString('takePhoto'), 79 loadTimeData.getString('photoFromCamera')); 80 81 $('take-photo').addEventListener( 82 'click', this.handleTakePhoto_.bind(this)); 83 $('discard-photo').addEventListener( 84 'click', this.handleDiscardPhoto_.bind(this)); 85 86 // Toggle 'animation' class for the duration of WebKit transition. 87 $('flip-photo').addEventListener( 88 'click', this.handleFlipPhoto_.bind(this)); 89 $('user-image-stream-crop').addEventListener( 90 'webkitTransitionEnd', function(e) { 91 previewElement.classList.remove('animation'); 92 }); 93 $('user-image-preview-img').addEventListener( 94 'webkitTransitionEnd', function(e) { 95 previewElement.classList.remove('animation'); 96 }); 97 98 // Old user image data (if present). 99 this.oldImage_ = null; 100 101 $('change-picture-overlay-confirm').addEventListener( 102 'click', this.closeOverlay_.bind(this)); 103 104 chrome.send('onChangePicturePageInitialized'); 105 }, 106 107 /** @override */ 108 didShowPage: function() { 109 var imageGrid = $('user-image-grid'); 110 // Reset camera element. 111 imageGrid.cameraImage = null; 112 imageGrid.updateAndFocus(); 113 chrome.send('onChangePicturePageShown'); 114 }, 115 116 /** @override */ 117 willHidePage: function() { 118 var imageGrid = $('user-image-grid'); 119 imageGrid.blur(); // Make sure the image grid is not active. 120 imageGrid.stopCamera(); 121 if (this.oldImage_) { 122 imageGrid.removeItem(this.oldImage_); 123 this.oldImage_ = null; 124 } 125 chrome.send('onChangePicturePageHidden'); 126 }, 127 128 /** 129 * Either willHidePage or didClosePage may be called depending on the way 130 * the page was closed. 131 * @override 132 */ 133 didClosePage: function() { 134 this.willHidePage(); 135 }, 136 137 /** 138 * Closes the overlay, returning to the main settings page. 139 * @private 140 */ 141 closeOverlay_: function() { 142 if (!$('change-picture-page').hidden) 143 PageManager.closeOverlay(); 144 }, 145 146 /** 147 * Handle camera-photo flip. 148 */ 149 handleFlipPhoto_: function() { 150 var imageGrid = $('user-image-grid'); 151 imageGrid.previewElement.classList.add('animation'); 152 imageGrid.flipPhoto = !imageGrid.flipPhoto; 153 var flipMessageId = imageGrid.flipPhoto ? 154 'photoFlippedAccessibleText' : 'photoFlippedBackAccessibleText'; 155 announceAccessibleMessage(loadTimeData.getString(flipMessageId)); 156 }, 157 158 /** 159 * Handles "Take photo" button click. 160 * @private 161 */ 162 handleTakePhoto_: function() { 163 $('user-image-grid').takePhoto(); 164 chrome.send('takePhoto'); 165 }, 166 167 /** 168 * Handle photo captured event. 169 * @param {Event} e Event with 'dataURL' property containing a data URL. 170 */ 171 handlePhotoTaken_: function(e) { 172 chrome.send('photoTaken', [e.dataURL]); 173 announceAccessibleMessage( 174 loadTimeData.getString('photoCaptureAccessibleText')); 175 }, 176 177 /** 178 * Handles "Discard photo" button click. 179 * @private 180 */ 181 handleDiscardPhoto_: function() { 182 $('user-image-grid').discardPhoto(); 183 chrome.send('discardPhoto'); 184 announceAccessibleMessage( 185 loadTimeData.getString('photoDiscardAccessibleText')); 186 }, 187 188 /** 189 * Handles "Choose a file" button activation. 190 * @private 191 */ 192 handleChooseFile_: function() { 193 chrome.send('chooseFile'); 194 this.closeOverlay_(); 195 }, 196 197 /** 198 * Handles image selection change. 199 * @param {Event} e Selection change Event. 200 * @private 201 */ 202 handleImageSelected_: function(e) { 203 var imageGrid = $('user-image-grid'); 204 var url = imageGrid.selectedItemUrl; 205 206 // Flip button available only for camera picture. 207 imageGrid.flipPhotoElement.tabIndex = 208 imageGrid.selectionType == 'camera' ? 1 : -1; 209 // Ignore selection change caused by program itself and selection of one 210 // of the action buttons. 211 if (!imageGrid.inProgramSelection && 212 url != ButtonImages.TAKE_PHOTO && url != ButtonImages.CHOOSE_FILE) { 213 chrome.send('selectImage', [url, imageGrid.selectionType]); 214 } 215 // Start/stop camera on (de)selection. 216 if (!imageGrid.inProgramSelection && 217 imageGrid.selectionType != e.oldSelectionType) { 218 if (imageGrid.selectionType == 'camera') { 219 imageGrid.startCamera( 220 function() { 221 // Start capture if camera is still the selected item. 222 return imageGrid.selectedItem == imageGrid.cameraImage; 223 }); 224 } else { 225 imageGrid.stopCamera(); 226 } 227 } 228 // Update image attribution text. 229 var image = imageGrid.selectedItem; 230 $('user-image-author-name').textContent = image.author; 231 $('user-image-author-website').textContent = image.website; 232 $('user-image-author-website').href = image.website; 233 $('user-image-attribution').style.visibility = 234 (image.author || image.website) ? 'visible' : 'hidden'; 235 }, 236 237 /** 238 * Handles image activation (by pressing Enter). 239 * @private 240 */ 241 handleImageActivated_: function() { 242 switch ($('user-image-grid').selectedItemUrl) { 243 case ButtonImages.TAKE_PHOTO: 244 this.handleTakePhoto_(); 245 break; 246 case ButtonImages.CHOOSE_FILE: 247 this.handleChooseFile_(); 248 break; 249 default: 250 this.closeOverlay_(); 251 break; 252 } 253 }, 254 255 /** 256 * Adds or updates old user image taken from file/camera (neither a profile 257 * image nor a default one). 258 * @param {string} imageUrl Old user image, as data or internal URL. 259 * @private 260 */ 261 setOldImage_: function(imageUrl) { 262 var imageGrid = $('user-image-grid'); 263 if (this.oldImage_) { 264 this.oldImage_ = imageGrid.updateItem(this.oldImage_, imageUrl); 265 } else { 266 // Insert next to the profile image. 267 var pos = imageGrid.indexOf(this.profileImage_) + 1; 268 this.oldImage_ = imageGrid.addItem(imageUrl, undefined, undefined, pos); 269 this.oldImage_.type = 'old'; 270 imageGrid.selectedItem = this.oldImage_; 271 } 272 }, 273 274 /** 275 * Updates user's profile image. 276 * @param {string} imageUrl Profile image, encoded as data URL. 277 * @param {boolean} select If true, profile image should be selected. 278 * @private 279 */ 280 setProfileImage_: function(imageUrl, select) { 281 var imageGrid = $('user-image-grid'); 282 this.profileImage_ = imageGrid.updateItem( 283 this.profileImage_, imageUrl, loadTimeData.getString('profilePhoto')); 284 if (select) 285 imageGrid.selectedItem = this.profileImage_; 286 }, 287 288 /** 289 * Selects user image with the given URL. 290 * @param {string} url URL of the image to select. 291 * @private 292 */ 293 setSelectedImage_: function(url) { 294 $('user-image-grid').selectedItemUrl = url; 295 }, 296 297 /** 298 * @param {boolean} present Whether camera is detected. 299 */ 300 setCameraPresent_: function(present) { 301 $('user-image-grid').cameraPresent = present; 302 }, 303 304 /** 305 * Appends default images to the image grid. Should only be called once. 306 * @param {Array.<{url: string, author: string, website: string}>} 307 * imagesData An array of default images data, including URL, author and 308 * website. 309 * @private 310 */ 311 setDefaultImages_: function(imagesData) { 312 var imageGrid = $('user-image-grid'); 313 for (var i = 0, data; data = imagesData[i]; i++) { 314 var item = imageGrid.addItem(data.url, data.title); 315 item.type = 'default'; 316 item.author = data.author || ''; 317 item.website = data.website || ''; 318 } 319 }, 320 }; 321 322 // Forward public APIs to private implementations. 323 cr.makePublic(ChangePictureOptions, [ 324 'closeOverlay', 325 'setCameraPresent', 326 'setDefaultImages', 327 'setOldImage', 328 'setProfileImage', 329 'setSelectedImage', 330 ]); 331 332 // Export 333 return { 334 ChangePictureOptions: ChangePictureOptions 335 }; 336 337}); 338