• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
26function 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
44Uploader.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 */
188function 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
205BackgroundPage.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 */
314var bg = new BackgroundPage();
315
316</script>
317</body>
318</html>
319