| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview Oobe user image screen implementation. |
| */ |
| |
| cr.define('login', function() { |
| var UserImagesGrid = options.UserImagesGrid; |
| var ButtonImages = UserImagesGrid.ButtonImages; |
| |
| /** |
| * Array of button URLs used on this page. |
| * @type {Array.<string>} |
| * @const |
| */ |
| var ButtonImageUrls = [ |
| ButtonImages.TAKE_PHOTO |
| ]; |
| |
| /** |
| * Whether the web camera item should be preselected, if available. |
| * @type {boolean} |
| * @const |
| */ |
| var PRESELECT_CAMERA = false; |
| |
| /** |
| * Creates a new OOBE screen div. |
| * @constructor |
| * @extends {HTMLDivElement} |
| */ |
| var UserImageScreen = cr.ui.define(login.Screen); |
| |
| /** |
| * Registers with Oobe. |
| * @param {boolean} lazyInit If true, screen is decorated on first show. |
| */ |
| UserImageScreen.register = function(lazyInit) { |
| var screen = $('user-image'); |
| if (lazyInit) { |
| screen.__proto__ = UserImageScreen.prototype; |
| screen.deferredDecorate = function() { |
| UserImageScreen.decorate(screen); |
| }; |
| } else { |
| UserImageScreen.decorate(screen); |
| } |
| Oobe.getInstance().registerScreen(screen); |
| }; |
| |
| UserImageScreen.prototype = { |
| __proto__: login.Screen.prototype, |
| |
| /** |
| * Currently selected user image index (take photo button is with zero |
| * index). |
| * @type {number} |
| */ |
| selectedUserImage_: -1, |
| |
| /** |
| * Indicates if profile picture should be displayed on current screen. |
| */ |
| profilePictureEnabled_: false, |
| |
| /** |
| * URL for profile picture. |
| */ |
| profileImageUrl_: null, |
| |
| /** @override */ |
| decorate: function(element) { |
| var imageGrid = $('user-image-grid'); |
| UserImagesGrid.decorate(imageGrid); |
| |
| // Preview image will track the selected item's URL. |
| var previewElement = $('user-image-preview'); |
| previewElement.oncontextmenu = function(e) { e.preventDefault(); }; |
| |
| imageGrid.previewElement = previewElement; |
| imageGrid.selectionType = 'default'; |
| |
| imageGrid.addEventListener('select', |
| this.handleSelect_.bind(this)); |
| imageGrid.addEventListener('activate', |
| this.handleImageActivated_.bind(this)); |
| imageGrid.addEventListener('phototaken', |
| this.handlePhotoTaken_.bind(this)); |
| imageGrid.addEventListener('photoupdated', |
| this.handlePhotoUpdated_.bind(this)); |
| |
| // Set the title for camera item in the grid. |
| imageGrid.setCameraTitles( |
| loadTimeData.getString('takePhoto'), |
| loadTimeData.getString('photoFromCamera')); |
| |
| this.setProfilePictureEnabled_(true); |
| |
| this.profileImageLoading = true; |
| |
| $('take-photo').addEventListener( |
| 'click', this.handleTakePhoto_.bind(this)); |
| $('discard-photo').addEventListener( |
| 'click', this.handleDiscardPhoto_.bind(this)); |
| |
| // Toggle 'animation' class for the duration of WebKit transition. |
| $('flip-photo').addEventListener( |
| 'click', function(e) { |
| previewElement.classList.add('animation'); |
| imageGrid.flipPhoto = !imageGrid.flipPhoto; |
| }); |
| $('user-image-stream-crop').addEventListener( |
| 'webkitTransitionEnd', function(e) { |
| previewElement.classList.remove('animation'); |
| }); |
| $('user-image-preview-img').addEventListener( |
| 'webkitTransitionEnd', function(e) { |
| previewElement.classList.remove('animation'); |
| }); |
| |
| this.updateLocalizedContent(); |
| |
| chrome.send('getImages'); |
| }, |
| |
| /** |
| * Header text of the screen. |
| * @type {string} |
| */ |
| get header() { |
| return loadTimeData.getString('userImageScreenTitle'); |
| }, |
| |
| /** |
| * Buttons in oobe wizard's button strip. |
| * @type {array} Array of Buttons. |
| */ |
| get buttons() { |
| var okButton = this.ownerDocument.createElement('button'); |
| okButton.id = 'ok-button'; |
| okButton.textContent = loadTimeData.getString('okButtonText'); |
| okButton.addEventListener('click', this.acceptImage_.bind(this)); |
| return [okButton]; |
| }, |
| |
| /** |
| * The caption to use for the Profile image preview. |
| * @type {string} |
| */ |
| get profileImageCaption() { |
| return this.profileImageCaption_; |
| }, |
| set profileImageCaption(value) { |
| this.profileImageCaption_ = value; |
| this.updateCaption_(); |
| }, |
| |
| /** |
| * True if the Profile image is being loaded. |
| * @type {boolean} |
| */ |
| get profileImageLoading() { |
| return this.profileImageLoading_; |
| }, |
| set profileImageLoading(value) { |
| this.profileImageLoading_ = value; |
| $('user-image-screen-main').classList[ |
| value ? 'add' : 'remove']('profile-image-loading'); |
| this.updateProfileImageCaption_(); |
| }, |
| |
| /** |
| * Handles image activation (by pressing Enter). |
| * @private |
| */ |
| handleImageActivated_: function() { |
| switch ($('user-image-grid').selectedItemUrl) { |
| case ButtonImages.TAKE_PHOTO: |
| this.handleTakePhoto_(); |
| break; |
| default: |
| this.acceptImage_(); |
| break; |
| } |
| }, |
| |
| /** |
| * Handles selection change. |
| * @param {cr.Event} e Selection change event. |
| * @private |
| */ |
| handleSelect_: function(e) { |
| var imageGrid = $('user-image-grid'); |
| if (imageGrid.selectionType == 'camera' && imageGrid.cameraLive) { |
| // No current image selected. |
| $('ok-button').disabled = true; |
| } else { |
| $('ok-button').disabled = false; |
| chrome.send('selectImage', |
| [imageGrid.selectedItemUrl, imageGrid.selectionType, |
| !imageGrid.inProgramSelection]); |
| } |
| // Start/stop camera on (de)selection. |
| if (!imageGrid.inProgramSelection && |
| imageGrid.selectionType != e.oldSelectionType) { |
| if (imageGrid.selectionType == 'camera') { |
| // Programmatic selection of camera item is done in |
| // startCamera callback where streaming is started by itself. |
| imageGrid.startCamera( |
| function() { |
| // Start capture if camera is still the selected item. |
| return imageGrid.selectedItem == imageGrid.cameraImage; |
| }); |
| } else { |
| imageGrid.stopCamera(); |
| } |
| } |
| this.updateCaption_(); |
| // Update image attribution text. |
| var image = imageGrid.selectedItem; |
| $('user-image-author-name').textContent = image.author; |
| $('user-image-author-website').textContent = image.website; |
| $('user-image-author-website').href = image.website; |
| $('user-image-attribution').style.visibility = |
| (image.author || image.website) ? 'visible' : 'hidden'; |
| }, |
| |
| /** |
| * Handle photo capture from the live camera stream. |
| */ |
| handleTakePhoto_: function(e) { |
| $('user-image-grid').takePhoto(); |
| }, |
| |
| /** |
| * Handle photo captured event. |
| * @param {cr.Event} e Event with 'dataURL' property containing a data URL. |
| */ |
| handlePhotoTaken_: function(e) { |
| chrome.send('photoTaken', [e.dataURL]); |
| this.announceAccessibleMessage_( |
| loadTimeData.getString('photoCaptureAccessibleText')); |
| }, |
| |
| /** |
| * Handle photo updated event. |
| * @param {cr.Event} e Event with 'dataURL' property containing a data URL. |
| */ |
| handlePhotoUpdated_: function(e) { |
| chrome.send('photoTaken', [e.dataURL]); |
| }, |
| |
| /** |
| * Handle discarding the captured photo. |
| */ |
| handleDiscardPhoto_: function(e) { |
| var imageGrid = $('user-image-grid'); |
| imageGrid.discardPhoto(); |
| this.announceAccessibleMessage_( |
| loadTimeData.getString('photoDiscardAccessibleText')); |
| }, |
| |
| /** |
| * Add an accessible message to the page that will be announced to |
| * users who have spoken feedback on, but will be invisible to all |
| * other users. It's removed right away so it doesn't clutter the DOM. |
| */ |
| announceAccessibleMessage_: function(msg) { |
| var element = document.createElement('div'); |
| element.setAttribute('aria-live', 'polite'); |
| element.style.position = 'relative'; |
| element.style.left = '-9999px'; |
| element.style.height = '0px'; |
| element.innerText = msg; |
| document.body.appendChild(element); |
| window.setTimeout(function() { |
| document.body.removeChild(element); |
| }, 0); |
| }, |
| |
| /** |
| * Event handler that is invoked just before the screen is shown. |
| * @param {object} data Screen init payload. |
| */ |
| onBeforeShow: function(data) { |
| Oobe.getInstance().headerHidden = true; |
| var imageGrid = $('user-image-grid'); |
| imageGrid.updateAndFocus(); |
| chrome.send('onUserImageScreenShown'); |
| }, |
| |
| /** |
| * Event handler that is invoked just before the screen is hidden. |
| */ |
| onBeforeHide: function() { |
| $('user-image-grid').stopCamera(); |
| }, |
| |
| /** |
| * Accepts currently selected image, if possible. |
| * @private |
| */ |
| acceptImage_: function() { |
| var okButton = $('ok-button'); |
| if (!okButton.disabled) { |
| // This ensures that #ok-button won't be re-enabled again. |
| $('user-image-grid').disabled = true; |
| okButton.disabled = true; |
| chrome.send('onUserImageAccepted'); |
| } |
| }, |
| |
| /** |
| * Updates user profile image. |
| * @param {?string} imageUrl Image encoded as data URL. If null, user has |
| * the default profile image, which we don't want to show. |
| * @private |
| */ |
| setProfileImage_: function(imageUrl) { |
| this.profileImageLoading = false; |
| this.profileImageUrl_ = imageUrl; |
| if (imageUrl !== null) { |
| this.profileImage_ = |
| $('user-image-grid').updateItem(this.profileImage_, imageUrl); |
| } |
| }, |
| |
| /** |
| * @param {boolean} present Whether camera is detected. |
| */ |
| setCameraPresent_: function(present) { |
| $('user-image-grid').cameraPresent = present; |
| }, |
| |
| /** |
| * Controls the profile image as one of image options. |
| * @param {enabled} Whether profile image option should be displayed. |
| * @private |
| */ |
| setProfilePictureEnabled_: function(enabled) { |
| if (this.profilePictureEnabled_ == enabled) |
| return; |
| this.profilePictureEnabled_ = enabled; |
| var imageGrid = $('user-image-grid'); |
| if (enabled) { |
| var url = ButtonImages.PROFILE_PICTURE; |
| if (!this.profileImageLoading && this.profileImageUrl_ !== null) { |
| url = this.profileImageUrl_; |
| } |
| // Profile image data (if present). |
| this.profileImage_ = imageGrid.addItem( |
| url, // Image URL. |
| loadTimeData.getString('profilePhoto'), // Title. |
| undefined, // Click handler. |
| 0, // Position. |
| this.profileImageLoading ? function(el) { |
| // Custom decorator for Profile image element. |
| var spinner = el.ownerDocument.createElement('div'); |
| spinner.className = 'spinner'; |
| var spinnerBg = el.ownerDocument.createElement('div'); |
| spinnerBg.className = 'spinner-bg'; |
| spinnerBg.appendChild(spinner); |
| el.appendChild(spinnerBg); |
| el.id = 'profile-image'; |
| } : undefined); |
| this.profileImage_.type = 'profile'; |
| } else { |
| imageGrid.removeItem(this.profileImage_); |
| } |
| }, |
| |
| /** |
| * Appends default images to the image grid. Should only be called once. |
| * @param {Array.<{url: string, author: string, website: string}>} images |
| * An array of default images data, including URL, author and website. |
| * @private |
| */ |
| setDefaultImages_: function(imagesData) { |
| var imageGrid = $('user-image-grid'); |
| for (var i = 0, data; data = imagesData[i]; i++) { |
| var item = imageGrid.addItem(data.url, data.title); |
| item.type = 'default'; |
| item.author = data.author || ''; |
| item.website = data.website || ''; |
| } |
| chrome.send('screenReady'); |
| }, |
| |
| /** |
| * Selects user image with the given URL. |
| * @param {string} url URL of the image to select. |
| * @private |
| */ |
| setSelectedImage_: function(url) { |
| var imageGrid = $('user-image-grid'); |
| imageGrid.selectedItemUrl = url; |
| imageGrid.focus(); |
| }, |
| |
| /** |
| * Hides curtain with spinner. |
| * @private |
| */ |
| hideCurtain_: function() { |
| this.classList.remove('loading'); |
| Oobe.getInstance().updateScreenSize(this); |
| }, |
| |
| /** |
| * Updates the image preview caption. |
| * @private |
| */ |
| updateCaption_: function() { |
| $('user-image-preview-caption').textContent = |
| $('user-image-grid').selectionType == 'profile' ? |
| this.profileImageCaption : ''; |
| }, |
| |
| /** |
| * Updates localized content of the screen that is not updated via template. |
| */ |
| updateLocalizedContent: function() { |
| this.updateProfileImageCaption_(); |
| }, |
| |
| /** |
| * Updates profile image caption. |
| * @private |
| */ |
| updateProfileImageCaption_: function() { |
| this.profileImageCaption = loadTimeData.getString( |
| this.profileImageLoading_ ? 'profilePhotoLoading' : 'profilePhoto'); |
| } |
| }; |
| |
| // Forward public APIs to private implementations. |
| [ |
| 'setDefaultImages', |
| 'setCameraPresent', |
| 'setProfilePictureEnabled', |
| 'setProfileImage', |
| 'setSelectedImage', |
| 'hideCurtain' |
| ].forEach(function(name) { |
| UserImageScreen[name] = function(value) { |
| $('user-image')[name + '_'](value); |
| }; |
| }); |
| |
| return { |
| UserImageScreen: UserImageScreen |
| }; |
| }); |
| |