Home | History | Annotate | Download | only in photo
      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 
      5 'use strict';
      6 
      7 
      8 /**
      9  * SelectAlbumDialog contains a message, a list box, an ok button, and a
     10  * cancel button.
     11  * Operates on a list of objects representing albums: { name, url, create }.
     12  * If user chooses to create a new album, result will be a fake album with
     13  * |create == true|.
     14  *
     15  * @param {HTMLElement} parentNode Node to be parent for this dialog.
     16  * @constructor
     17  */
     18 function SelectAlbumDialog(parentNode) {
     19   this.parentNode_ = parentNode;
     20   this.document_ = parentNode.ownerDocument;
     21 
     22   this.container_ = this.document_.createElement('div');
     23   this.container_.className = 'select-album-dialog-container';
     24   this.container_.addEventListener('keydown',
     25       this.onContainerKeyDown_.bind(this));
     26 
     27   this.shield_ = this.document_.createElement('div');
     28   this.shield_.className = 'select-album-dialog-shield';
     29   this.container_.appendChild(this.shield_);
     30 
     31   this.frame_ = this.document_.createElement('div');
     32   this.frame_.className = 'select-album-dialog-frame';
     33   this.container_.appendChild(this.frame_);
     34 
     35   this.caption_ = this.document_.createElement('div');
     36   this.caption_.className = 'select-album-dialog-caption';
     37   this.frame_.appendChild(this.caption_);
     38 
     39   this.list_ = new cr.ui.List();
     40   this.list_.classList.add('select-album-list');
     41   this.frame_.appendChild(this.list_);
     42 
     43   this.dataModel_ = this.list_.dataModel = new cr.ui.ArrayDataModel([]);
     44   this.selectionModel_ = this.list_.selectionModel =
     45       new cr.ui.ListSingleSelectionModel();
     46   this.selectionModel_.addEventListener('change',
     47       this.onSelectionChanged_.bind(this));
     48 
     49   // TODO(dgozman): add shades at top and bottom of the list.
     50   // List has max-height defined at css, so that list grows automatically,
     51   // but doesn't exceed predefined size.
     52   this.list_.autoExpands = true;
     53   this.list_.activateItemAtIndex = this.activateItemAtIndex_.bind(this);
     54   // Binding stuff doesn't work with constructors, so we have to create
     55   // closure here.
     56   var self = this;
     57   this.list_.itemConstructor = function(item) {
     58     return self.renderItem(item);
     59   };
     60 
     61   var buttons = this.document_.createElement('div');
     62   buttons.className = 'select-album-dialog-buttons';
     63   this.frame_.appendChild(buttons);
     64 
     65   this.okButton_ = this.document_.createElement('button');
     66   this.okButton_.className = 'no-icon';
     67   this.okButton_.addEventListener('click', this.onOkClick_.bind(this));
     68   buttons.appendChild(this.okButton_);
     69 
     70   this.cancelButton_ = this.document_.createElement('button');
     71   this.cancelButton_.className = 'no-icon';
     72   this.cancelButton_.textContent =
     73       loadTimeData.getString('PHOTO_IMPORT_CANCEL_BUTTON');
     74   this.cancelButton_.addEventListener('click', this.onCancelClick_.bind(this));
     75   buttons.appendChild(this.cancelButton_);
     76 
     77   this.nameEdit_ = this.document_.createElement('input');
     78   this.nameEdit_.setAttribute('type', 'text');
     79   this.nameEdit_.className = 'name';
     80   this.nameEdit_.addEventListener('input',
     81       this.updateOkButtonEnabled_.bind(this));
     82 }
     83 
     84 SelectAlbumDialog.prototype = {
     85   __proto__: cr.ui.dialogs.BaseDialog.prototype
     86 };
     87 
     88 /**
     89  * Renders item for list.
     90  * @param {Object} item Item to render.
     91  * @return {HTMLLIElement} Rendered item.
     92  */
     93 SelectAlbumDialog.prototype.renderItem = function(item) {
     94   var result = this.document_.createElement('li');
     95 
     96   var frame = this.document_.createElement('div');
     97   frame.className = 'img-frame';
     98   result.appendChild(frame);
     99 
    100   var box = this.document_.createElement('div');
    101   box.className = 'img-container';
    102   frame.appendChild(box);
    103 
    104   if (item.create) {
    105     result.appendChild(this.nameEdit_);
    106     this.nameEdit_.value = item.name;
    107   } else {
    108     var name = this.document_.createElement('div');
    109     name.className = 'name';
    110     name.textContent = item.name;
    111     result.appendChild(name);
    112   }
    113 
    114   cr.defineProperty(result, 'lead', cr.PropertyKind.BOOL_ATTR);
    115   cr.defineProperty(result, 'selected', cr.PropertyKind.BOOL_ATTR);
    116 
    117   new ThumbnailLoader(item.url).load(box, ThumbnailLoader.FillMode.FILL);
    118 
    119   return result;
    120 };
    121 
    122 /**
    123  * Shows dialog.
    124  *
    125  * @param {string} message Message in dialog caption.
    126  * @param {Array} items Albums to render in list.
    127  * @param {string} defaultNewName Default name of the new album.
    128  * @param {string} okCaption Text on the ok button.
    129  * @param {function} onOk Callback function.
    130  */
    131 SelectAlbumDialog.prototype.show = function(
    132     message, items, defaultNewName, okCaption, onOk) {
    133 
    134   this.onOk_ = onOk;
    135   this.okButton_.textContent = okCaption;
    136   this.caption_.textContent = message;
    137 
    138    // Fake item to create new album.
    139   var newAlbum = {
    140     create: true,
    141     name: defaultNewName,
    142     url: chrome.extension.getURL('../../images/photo/new_album.png')
    143   };
    144 
    145   this.list_.startBatchUpdates();
    146   this.dataModel_.splice(0, this.dataModel_.length);
    147   this.dataModel_.push(newAlbum);
    148   for (var i = 0; i < items.length; i++) {
    149     this.dataModel_.push(items[i]);
    150   }
    151   this.selectionModel_.selectedIndex = 0;
    152   this.list_.endBatchUpdates();
    153 
    154   this.parentNode_.appendChild(this.container_);
    155 };
    156 
    157 /**
    158  * Hides dialog.
    159  */
    160 SelectAlbumDialog.prototype.hide = function() {
    161   this.parentNode_.removeChild(this.container_);
    162 };
    163 
    164 /**
    165  * List activation handler. Closes dialog and calls 'ok' callback.
    166  *
    167  * @param {number} index Activated index.
    168  * @private
    169  */
    170 SelectAlbumDialog.prototype.activateItemAtIndex_ = function(index) {
    171   if (this.okButton_.disabled) return;
    172   this.hide();
    173   var album = this.dataModel_.item(index);
    174   if (index == 0)
    175     album.name = this.nameEdit_.value;
    176   this.onOk_(album);
    177 };
    178 
    179 /**
    180  * Closes dialog and invokes callback with currently-selected item.
    181  * @private
    182  */
    183 SelectAlbumDialog.prototype.onOkClick_ = function() {
    184   this.activateItemAtIndex_(this.selectionModel_.selectedIndex);
    185 };
    186 
    187 /**
    188  * Closes dialog.
    189  * @private
    190  */
    191 SelectAlbumDialog.prototype.onCancelClick_ = function() {
    192   this.hide();
    193 };
    194 
    195 /**
    196  * Event handler for keydown event.
    197  * @param {Event} event The event.
    198  * @private
    199  */
    200 SelectAlbumDialog.prototype.onContainerKeyDown_ = function(event) {
    201   // Handle Escape.
    202   if (event.keyCode == 27) {
    203     this.onCancelClick_(event);
    204     event.preventDefault();
    205   } else if (event.keyCode == 13) {
    206     this.onOkClick_();
    207     event.preventDefault();
    208   }
    209 };
    210 
    211 /**
    212  * Event handler for selection change.
    213  * @param {Event} event The event.
    214  * @private
    215  */
    216 SelectAlbumDialog.prototype.onSelectionChanged_ = function(event) {
    217   if (this.selectionModel_.selectedIndex == 0) {
    218     setTimeout(this.nameEdit_.focus.bind(this.nameEdit_), 0);
    219   } else {
    220     this.nameEdit_.blur();
    221     this.list_.focus();
    222   }
    223   this.updateOkButtonEnabled_();
    224 };
    225 
    226 /**
    227  * Updates ok button.
    228  * @private
    229  */
    230 SelectAlbumDialog.prototype.updateOkButtonEnabled_ = function() {
    231   this.okButton_.disabled = this.selectionModel_.selectedIndex == 0 &&
    232       this.nameEdit_.value == '';
    233 };
    234