<!DOCTYPE html> <html> <head> <script src="chrome://resources/js/cr.js"></script> <script src="chrome://resources/js/cr/event_target.js"></script> <script src="js/picasa_client.js"></script> </head> <body> <script> /** * Uploader constructor. * * Uploader object is responsible for uploading a bunch of images to the same * picasa album. It also manages the notification. * * @param {Array.<picasa.LocalFile>} files Files to upload. * @param {picasa.Album} album Album to upload to. * @param {picasa.Client} client Picasa client. * @param {string} hash Hash value unique to this uploader (to differentiate * multiple uploaders). */ function Uploader(files, album, client, hash) { this.album_ = album; this.client_ = client; this.files_ = files; this.filesTotal_ = this.files_.length; this.filesDone_ = 0; this.hash = hash; this.request_ = null; this.failed_ = false; this.canceled_ = false; this.finished_ = false; this.startDate_ = null; this.timeRemaining_ = null; } Uploader.prototype = { /** * Starts the upload process. */ start: function() { this.startDate_ = new Date(); this.failed_ = false; this.createNotification_(); var self = this; self.uploadNextFile_(); }, /** * Creates a webkit notification. */ createNotification_: function() { // We pass unique hash to the notification dom, so it will distinct this // uploader object from others. this.webkitNotification_ = window.webkitNotifications.createHTMLNotification( chrome.extension.getURL('notification.html' + this.hash)); this.webkitNotification_.onclose = this.onNotificationClose_.bind(this); this.webkitNotification_.show(); }, /** * Sets the notification object (see notification.html). * This method is called from notification dom, so uploader can modify it. * @param {Notification} notification The notification object. */ setNotification: function(notification) { this.notification_ = notification; if (this.finished_) { this.showFinished_(); } else { this.updateNotification_(); } }, /** * Updates information in notification. */ updateNotification_: function() { this.notification_.update(this.filesDone_, this.filesTotal_, this.timeRemaining_); }, /** * This method is called when uploading is finished (either successfully or * not). */ done_: function() { this.finished_ = true; // If notification was closed by user, we should create a new one. if (this.webkitNotification_) { this.showFinished_(); } else { this.createNotification_(); } }, /** * Shows final information in notification. */ showFinished_: function() { if (this.failed_) { this.notification_.showFailed(this.filesDone_, this.filesTotal_); } else if (this.canceled_) { this.notification_.showCanceled(this.filesDone_, this.filesTotal_); } else { this.notification_.showCompleted(this.filesDone_, this.album_.link); } }, /** * Event handler for notification close. */ onNotificationClose_: function() { if (this.finished_) { // Inform background page that we are done. bg.removeUploader(this.hash); } else { // User closed notification "in progress". We will create a new one // to show final information. this.webkitNotification_ = null; } }, /** * Uploads the next file to picasa web albums. */ uploadNextFile_: function() { if (this.files_.length == 0 || this.failed_ || this.canceled_) { this.done_(); return; } var file = this.files_.shift(); this.request_ = this.client_.uploadFile(this.album_, file, this.uploadFileCallback_.bind(this)); }, /** * Event handler for file upload. * @param {?string} response The response or null if failed. */ uploadFileCallback_: function(response) { if (this.failed_ || this.canceled_) { return; } this.request_ = null; if (response == null) { this.failed_ = true; } else { this.filesDone_++; var elapsed = (new Date()) - this.startDate_; this.timeRemaining_ = elapsed * (this.filesTotal_ - this.filesDone_) / this.filesDone_; } this.updateNotification_(); this.uploadNextFile_(); }, /** * Cancels the upload process. */ cancel: function() { this.canceled_ = true; this.done_(); if (this.request_) { this.request_.abort(); this.request_ = null; } } }; /** * BackgroundPage constructor. * * BackgroundPage object opens the upload window and passes upload requests * to Uploader objects. It also holds the global picasa client object. */ function BackgroundPage() { this.client = new picasa.Client(); this.newFiles_ = []; this.uploadPageUrl_ = chrome.extension.getURL('upload.html'); this.uploaders_ = {}; this.lastUploaderHash_ = 0; var self = this; chrome.fileBrowserHandler.onExecute.addListener( function(id, file_entries) { console.log('picasa: got task - ' + id); if (id == 'upload') { self.onFileUpload_(file_entries); } }); } BackgroundPage.prototype = { /** * Returns a window with specified url. * @param {string} url Url of a window to find. * @return {DOMWindow} Window with specified url. */ findWindow_: function(url) { var views = chrome.extension.getViews(); for (var view, i = 0; view = views[i]; i++) { if (view.location.href == url) { return view; } } return null; }, /** * Event handler called when user chooses "send to picasa" somewhere. * @param {Array.<picasa.LocalFile>} files Files to upload. */ onSendImageRequest_: function(files) { var win = this.findWindow_(this.uploadPageUrl_); if (win) { // If upload window already loaded, just add one more file. win.uploadPage.addFiles(files); } else { // If upload window is not yet loaded, it will ask for new files via // getNewFiles method. this.newFiles_ = this.newFiles_.concat(files); chrome.windows.create({url: this.uploadPageUrl_, width: 620, height: 465}); } }, /** * "Send to picasa" event handler from filebrowser. * @param {*} fileEntries Entry object array. */ onFileUpload_: function(fileEntries) { if (!fileEntries) { return; } var self = this; var files = []; var remaining = fileEntries.length; console.log('got files: ' + remaining); for (var i = 0; i < fileEntries.length; i++) { var entry = fileEntries[i]; entry.file(function(file) { files.push(new picasa.LocalFile(file)); remaining--; if (remaining == 0 && files.length > 0) { self.onSendImageRequest_(files); } }); } // If not all the entries were resolved, send request for resolved ones. setTimeout(function() { if (remaining > 0 && files.length > 0) { self.onSendImageRequest_(files); } }, 1000); }, /** * Returns new files for upload. * @return {Array.<picasa.LocalFile>} New files. */ getNewFiles: function() { var result = this.newFiles_; this.newFiles_ = []; return result; }, /** * Starts the uploading process. * @param {Array.<picasa.LocalFile>} files Files to upload. * @param {picasa.Album} album Album to upload to. */ uploadFiles: function(files, album) { var hash = '#' + this.lastUploaderHash_++; var uploader = new Uploader(files, album, this.client, hash); this.uploaders_[hash] = uploader; uploader.start(); }, /** * Returns an Uploader object by hash. * @param {string} hash Unique hash. * @return {Uploader} Uploader object with given hash. */ getUploader: function(hash) { return this.uploaders_[hash]; }, /** * Removes an Uploader object by hash. * @param {string} hash Unique hash. */ removeUploader: function(hash) { this.uploaders_[hash] = null; } }; /** * Single BackgroundPage object. * @type {BackgroundPage} */ var bg = new BackgroundPage(); </script> </body> </html>