text: // 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
    };
  });
  
  