Home | History | Annotate | Download | only in picasaweb_uploader
      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4   <script src="chrome://resources/js/cr.js"></script>
      5   <script src="chrome://resources/js/cr/event_target.js"></script>
      6 
      7   <script src="js/picasa_client.js"></script>
      8 </head>
      9 
     10 <body>
     11 
     12 <script>
     13 
     14 /**
     15  * Uploader constructor.
     16  *
     17  * Uploader object is responsible for uploading a bunch of images to the same
     18  * picasa album. It also manages the notification.
     19  *
     20  * @param {Array.<picasa.LocalFile>} files Files to upload.
     21  * @param {picasa.Album} album Album to upload to.
     22  * @param {picasa.Client} client Picasa client.
     23  * @param {string} hash Hash value unique to this uploader (to differentiate
     24  *     multiple uploaders).
     25  */
     26 function Uploader(files, album, client, hash) {
     27   this.album_ = album;
     28   this.client_ = client;
     29   this.files_ = files;
     30 
     31   this.filesTotal_ = this.files_.length;
     32   this.filesDone_ = 0;
     33   this.hash = hash;
     34 
     35   this.request_ = null;
     36   this.failed_ = false;
     37   this.canceled_ = false;
     38   this.finished_ = false;
     39 
     40   this.startDate_ = null;
     41   this.timeRemaining_ = null;
     42 }
     43 
     44 Uploader.prototype = {
     45   /**
     46    * Starts the upload process.
     47    */
     48   start: function() {
     49     this.startDate_ = new Date();
     50     this.failed_ = false;
     51     this.createNotification_();
     52     var self = this;
     53     self.uploadNextFile_();
     54   },
     55 
     56   /**
     57    * Creates a webkit notification.
     58    */
     59   createNotification_: function() {
     60     // We pass unique hash to the notification dom, so it will distinct this
     61     // uploader object from others.
     62     this.webkitNotification_ =
     63         window.webkitNotifications.createHTMLNotification(
     64             chrome.extension.getURL('notification.html' + this.hash));
     65     this.webkitNotification_.onclose = this.onNotificationClose_.bind(this);
     66     this.webkitNotification_.show();
     67   },
     68 
     69   /**
     70    * Sets the notification object (see notification.html).
     71    * This method is called from notification dom, so uploader can modify it.
     72    * @param {Notification} notification The notification object.
     73    */
     74   setNotification: function(notification) {
     75     this.notification_ = notification;
     76     if (this.finished_) {
     77       this.showFinished_();
     78     } else {
     79       this.updateNotification_();
     80     }
     81   },
     82 
     83   /**
     84    * Updates information in notification.
     85    */
     86   updateNotification_: function() {
     87     this.notification_.update(this.filesDone_, this.filesTotal_,
     88         this.timeRemaining_);
     89   },
     90 
     91   /**
     92    * This method is called when uploading is finished (either successfully or
     93    * not).
     94    */
     95   done_: function() {
     96     this.finished_ = true;
     97     // If notification was closed by user, we should create a new one.
     98     if (this.webkitNotification_) {
     99       this.showFinished_();
    100     } else {
    101       this.createNotification_();
    102     }
    103   },
    104 
    105   /**
    106    * Shows final information in notification.
    107    */
    108   showFinished_: function() {
    109     if (this.failed_) {
    110       this.notification_.showFailed(this.filesDone_, this.filesTotal_);
    111     } else if (this.canceled_) {
    112       this.notification_.showCanceled(this.filesDone_, this.filesTotal_);
    113     } else {
    114       this.notification_.showCompleted(this.filesDone_, this.album_.link);
    115     }
    116   },
    117 
    118   /**
    119    * Event handler for notification close.
    120    */
    121   onNotificationClose_: function() {
    122     if (this.finished_) {
    123       // Inform background page that we are done.
    124       bg.removeUploader(this.hash);
    125     } else {
    126       // User closed notification "in progress". We will create a new one
    127       // to show final information.
    128       this.webkitNotification_ = null;
    129     }
    130   },
    131 
    132   /**
    133    * Uploads the next file to picasa web albums.
    134    */
    135   uploadNextFile_: function() {
    136     if (this.files_.length == 0 || this.failed_ || this.canceled_) {
    137       this.done_();
    138       return;
    139     }
    140 
    141     var file = this.files_.shift();
    142     this.request_ = this.client_.uploadFile(this.album_, file,
    143         this.uploadFileCallback_.bind(this));
    144   },
    145 
    146   /**
    147    * Event handler for file upload.
    148    * @param {?string} response The response or null if failed.
    149    */
    150   uploadFileCallback_: function(response) {
    151     if (this.failed_ || this.canceled_) {
    152       return;
    153     }
    154     
    155     this.request_ = null;
    156     if (response == null) {
    157       this.failed_ = true;
    158     } else {
    159       this.filesDone_++;
    160       var elapsed = (new Date()) - this.startDate_;
    161       this.timeRemaining_ = elapsed *
    162           (this.filesTotal_ - this.filesDone_) / this.filesDone_;
    163     }
    164     this.updateNotification_();
    165     this.uploadNextFile_();
    166   },
    167 
    168   /**
    169    * Cancels the upload process.
    170    */
    171   cancel: function() {
    172     this.canceled_ = true;
    173     this.done_();
    174     if (this.request_) {
    175       this.request_.abort();
    176       this.request_ = null;
    177     }
    178   }
    179 };
    180 
    181 
    182 /**
    183  * BackgroundPage constructor.
    184  *
    185  * BackgroundPage object opens the upload window and passes upload requests
    186  * to Uploader objects. It also holds the global picasa client object.
    187  */
    188 function BackgroundPage() {
    189   this.client = new picasa.Client();
    190   this.newFiles_ = [];
    191   this.uploadPageUrl_ = chrome.extension.getURL('upload.html');
    192   this.uploaders_ = {};
    193   this.lastUploaderHash_ = 0;
    194 
    195   var self = this;
    196   chrome.fileBrowserHandler.onExecute.addListener(
    197     function(id, file_entries) {
    198       console.log('picasa: got task - ' + id);
    199       if (id == 'upload') {
    200         self.onFileUpload_(file_entries);
    201       }
    202     });
    203 }
    204 
    205 BackgroundPage.prototype = {
    206   /**
    207    * Returns a window with specified url.
    208    * @param {string} url Url of a window to find.
    209    * @return {DOMWindow} Window with specified url.
    210    */
    211   findWindow_: function(url) {
    212     var views = chrome.extension.getViews();
    213     for (var view, i = 0; view = views[i]; i++) {
    214       if (view.location.href == url) {
    215         return view;
    216       }
    217     }
    218     return null;
    219   },
    220 
    221   /**
    222    * Event handler called when user chooses "send to picasa" somewhere. 
    223    * @param {Array.<picasa.LocalFile>} files Files to upload.
    224    */
    225   onSendImageRequest_: function(files) {
    226     var win = this.findWindow_(this.uploadPageUrl_);
    227     if (win) {
    228       // If upload window already loaded, just add one more file.
    229       win.uploadPage.addFiles(files);
    230     } else {
    231       // If upload window is not yet loaded, it will ask for new files via
    232       // getNewFiles method.
    233       this.newFiles_ = this.newFiles_.concat(files);
    234       chrome.windows.create({url: this.uploadPageUrl_, width: 620, height: 465});
    235     }
    236   },
    237 
    238   /**
    239    * "Send to picasa" event handler from filebrowser.
    240    * @param {*} fileEntries Entry object array.
    241    */
    242   onFileUpload_: function(fileEntries) {
    243     if (!fileEntries) {
    244       return;
    245     }
    246 
    247     var self = this;
    248     var files = [];
    249     var remaining = fileEntries.length;
    250     console.log('got files: ' + remaining);
    251     for (var i = 0; i < fileEntries.length; i++) {
    252       var entry = fileEntries[i];
    253       entry.file(function(file) {
    254         files.push(new picasa.LocalFile(file));
    255         remaining--;
    256         if (remaining == 0 && files.length > 0) {
    257           self.onSendImageRequest_(files);
    258         }
    259       });
    260     }
    261 
    262     // If not all the entries were resolved, send request for resolved ones.
    263     setTimeout(function() {
    264       if (remaining > 0 && files.length > 0) {
    265         self.onSendImageRequest_(files);
    266       }
    267     }, 1000);
    268   },
    269 
    270   /**
    271    * Returns new files for upload.
    272    * @return {Array.<picasa.LocalFile>} New files.
    273    */
    274   getNewFiles: function() {
    275     var result = this.newFiles_;
    276     this.newFiles_ = [];
    277     return result;
    278   },
    279 
    280   /**
    281    * Starts the uploading process.
    282    * @param {Array.<picasa.LocalFile>} files Files to upload.
    283    * @param {picasa.Album} album Album to upload to.
    284    */
    285   uploadFiles: function(files, album) {
    286     var hash = '#' + this.lastUploaderHash_++;
    287     var uploader = new Uploader(files, album, this.client, hash);
    288     this.uploaders_[hash] = uploader;
    289     uploader.start();
    290   },
    291 
    292   /**
    293    * Returns an Uploader object by hash.
    294    * @param {string} hash Unique hash.
    295    * @return {Uploader} Uploader object with given hash.
    296    */
    297   getUploader: function(hash) {
    298     return this.uploaders_[hash];
    299   },
    300 
    301   /**
    302    * Removes an Uploader object by hash.
    303    * @param {string} hash Unique hash.
    304    */
    305   removeUploader: function(hash) {
    306     this.uploaders_[hash] = null;
    307   }
    308 };
    309 
    310 /**
    311  * Single BackgroundPage object.
    312  * @type {BackgroundPage}
    313  */
    314 var bg = new BackgroundPage();
    315 
    316 </script>
    317 </body>
    318 </html>
    319