Release 5.2
diff --git a/src/js/upload_ui.js b/src/js/upload_ui.js
new file mode 100644
index 0000000..5b073f5
--- /dev/null
+++ b/src/js/upload_ui.js
@@ -0,0 +1,487 @@
+const CURRENT_LOCALE = chrome.i18n.getMessage('@@ui_locale');
+const MULTIPART_FORMDATA_BOUNDARY = 'Google_Chrome_Screen_Capture';
+const HIDE_ERROR_INFO_DELAY_TIME = 5000;
+
+var UploadUI = {
+ currentSite: '',
+ uploading: false,
+ sites: {},
+
+ registerSite: function(id, siteObject) {
+ this.sites[id] = siteObject;
+ },
+
+ getSiteObject: function(id) {
+ return this.sites[id];
+ },
+
+ setUploading: function(state) {
+ UploadUI.uploading = state;
+ },
+
+ init: function() {
+ // Register supported site for image sharing.
+ UploadUI.registerSite(SinaMicroblog.siteId, SinaMicroblog);
+ UploadUI.registerSite(Facebook.siteId, Facebook);
+ UploadUI.registerSite(Picasa.siteId, Picasa);
+ UploadUI.registerSite(Imgur.siteId, Imgur);
+
+ // Import style sheet for current locale
+ if (CURRENT_LOCALE == 'zh_CN')
+ UI.addStyleSheet('./i18n_styles/zh_CN_upload_image.css');
+ else
+ UI.addStyleSheet('./i18n_styles/en_US_upload_image.css');
+
+ // Get i18n message
+ i18nReplace('shareToSinaMicroblogText', SinaMicroblog.siteId +
+ '_upload_header');
+ i18nReplace('shareToFacebookText', Facebook.siteId + '_upload_header');
+ i18nReplace('shareToPicasaText', Picasa.siteId + '_upload_header');
+ i18nReplace('lastStep', 'return_to_site_selection');
+ i18nReplace('closeUploadWrapper', 'close_upload_wrapper');
+ i18nReplace('imageCaptionText', 'image_caption');
+ i18nReplace('photoSizeTip', 'photo_size_tip');
+ i18nReplace('shareToImgurText', Imgur.siteId + '_upload_header');
+ $('requiredFlag').setAttribute('title',
+ chrome.i18n.getMessage('invalid_caption'));
+
+ // Add event listeners
+ //$('btnUpload').addEventListener('click', UploadUI.showUploadWrapper, false);
+ $('btnSave').addEventListener('click', UploadUI.saveImage, false);
+ $('closeUploadWrapper').addEventListener('click',
+ UploadUI.hideUploadWrapper, false);
+
+ $('picasaBtn').addEventListener('click', function() {
+ UploadUI.showUploadContentWrapper(Picasa.siteId);
+ });
+ $('facebookBtn').addEventListener('click', function() {
+ UploadUI.showUploadContentWrapper(Facebook.siteId);
+ }, false);
+ $('sinaMicroblogBtn').addEventListener('click', function() {
+ UploadUI.showUploadContentWrapper(SinaMicroblog.siteId);
+ }, false);
+ $('imgurBtn').addEventListener('click', function() {
+ UploadUI.showUploadContentWrapper(Imgur.siteId);
+ }, false);
+ $('shareToOtherAccount').addEventListener('click', function() {
+ var currentSite = UploadUI.currentSite;
+
+ // Validate image description first
+ if (UploadUI.validatePhotoDescription(currentSite)) {
+ var callback = function() {
+ var authenticationTip =
+ chrome.i18n.getMessage('user_authentication_tip');
+ UploadUI.showAuthenticationProgress(authenticationTip);
+ UploadUI.getAccessToken(currentSite);
+ };
+ var users = Account.getUsers(currentSite);
+ var numberOfUsers = Object.keys(users).length;
+
+ // Logout when user has authenticated app
+ if (numberOfUsers) {
+ var logoutTip = chrome.i18n.getMessage('user_logout_tip');
+ UploadUI.showAuthenticationProgress(logoutTip);
+ var site = UploadUI.getSiteObject(currentSite);
+ site.logout(callback);
+ } else {
+ callback();
+ }
+ }
+ }, false);
+ $('lastStep').addEventListener('click', UploadUI.showUploadSitesWrapper,
+ false);
+ },
+
+ showUploadWrapper: function() {
+ var uploadWrapper = $('uploadWrapper');
+ UI.show(uploadWrapper);
+
+ // Reset upload wrapper position
+ var viewportWidth = window.innerWidth;
+ var viewportHeight = window.innerHeight;
+ var wrapperWidth = uploadWrapper.offsetWidth;
+ var wrapperHeight = uploadWrapper.offsetHeight;
+
+ var left = (viewportWidth - wrapperWidth) / 2;
+ var top = (viewportHeight - wrapperHeight) / 3;
+ left = left < 0 ? 0 : left;
+ top = top < 0 ? 0 : top;
+
+ var scrollTop = document.body.scrollTop;
+ var scrollLeft = document.body.scrollLeft;
+
+ UI.setStyle(uploadWrapper, {
+ top: top + scrollTop + 'px',
+ left: left + scrollLeft + 'px'
+ });
+ UploadUI.showUploadSitesWrapper();
+ UploadUI.showOverlay();
+ },
+
+ hideUploadWrapper: function() {
+ UI.hide($('uploadWrapper'));
+ UploadUI.hideOverlay();
+ },
+
+ showOverlay: function() {
+ var overlay = $('overlay');
+ UI.setStyle(overlay, {
+ width: document.body.scrollWidth + 'px',
+ height: document.body.scrollHeight + 'px'
+ });
+ UI.show($('overlay'));
+ },
+
+ hideOverlay: function() {
+ UI.hide($('overlay'));
+ },
+
+ updateUploadHeader: function(title) {
+ $('uploadHeader').firstElementChild.firstElementChild.innerText = title;
+ },
+
+ showUploadSitesWrapper: function() {
+ var uploadHeader = chrome.i18n.getMessage('upload_sites_header');
+ UploadUI.updateUploadHeader(uploadHeader);
+ UI.show($('uploadSitesWrapper'));
+ UploadUI.hideUploadContentWrapper();
+ UI.hide($('lastStep'));
+ },
+
+ hideUploadSitesWrapper: function() {
+ UI.hide($('uploadSitesWrapper'));
+ },
+
+ showUploadContentWrapper: function(site) {
+ UploadUI.currentSite = site;
+
+ // Update upload wrapper UI
+ var uploadHeader = chrome.i18n.getMessage(site + '_upload_header');
+ UploadUI.updateUploadHeader(uploadHeader);
+ UploadUI.hideUploadSitesWrapper();
+ UploadUI.hideErrorInfo();
+ UploadUI.hideAuthenticationProgress();
+ UploadUI.clearPhotoDescription();
+ UI.show($('uploadContentWrapper'));
+ UI.show($('lastStep'));
+ UploadUI.updateShareToOtherAccountText(site);
+ UploadUI.togglePhotoDescriptionRequiredFlag(site);
+
+ // Show authenticated accounts of current site
+ UploadUI.clearAccounts();
+ var users = Account.getUsers(site);
+ for (var userId in users) {
+ UploadUI.addAuthenticatedAccount(site, userId);
+ }
+ },
+
+ hideUploadContentWrapper: function() {
+ UI.hide($('uploadContentWrapper'));
+ },
+
+ clearPhotoDescription: function() {
+ $('imageCaption').value = '';
+ },
+
+ validatePhotoDescription: function(site) {
+ var caption = $('imageCaption');
+ var invalidCaptionMsg = chrome.i18n.getMessage('invalid_caption');
+
+ // Validate photo description
+ if (site == SinaMicroblog.siteId && caption.value == '') {
+ UploadUI.showErrorInfo(invalidCaptionMsg);
+ caption.focus();
+ return false;
+ }
+ return true;
+ },
+
+ togglePhotoDescriptionRequiredFlag: function(siteId) {
+ if (siteId == SinaMicroblog.siteId)
+ UI.show($('requiredFlag'));
+ else
+ UI.hide($('requiredFlag'));
+ },
+
+ updateShareToOtherAccountText: function(siteId) {
+ var users = Account.getUsers(siteId);
+ var userLength = Object.keys(users).length;
+ if (userLength)
+ i18nReplace('shareToOtherAccount', 'share_to_other_account');
+ else
+ i18nReplace('shareToOtherAccount', 'share_to_' + siteId + '_account');
+ },
+
+ showErrorInfo: function(text) {
+ UI.show($('errorWrapper'));
+ $('errorInfo').innerHTML = text;
+ setTimeout(function() {
+ UploadUI.hideErrorInfo();
+ }, HIDE_ERROR_INFO_DELAY_TIME);
+ },
+
+ hideErrorInfo: function() {
+ UI.hide($('errorWrapper'));
+ },
+
+ showProgressBar: function(accountId) {
+ var progress = document.querySelector('#' + accountId +
+ ' .progressBar');
+ UI.show(progress);
+ },
+
+ hideProgressBar: function(accountId) {
+ var progress = document.querySelector('#' + accountId +
+ ' .progressBar');
+ UI.hide(progress);
+ },
+
+ showAuthenticationProgress: function(title) {
+ var progress = $('authenticationProgress');
+ progress.setAttribute('title', title);
+ UI.show(progress);
+ },
+
+ hideAuthenticationProgress: function() {
+ UI.hide($('authenticationProgress'));
+ },
+
+ setProgress: function(accountId, loaded, total) {
+ console.log('In setProgress, loaded: ' + loaded + ', total: ' + total);
+ var progress = document.querySelector('#' + accountId + ' .progressBar');
+
+ // One progress bar has 4 parts to represent progress
+ var level = parseInt(loaded / total / 0.25);
+ UI.setStyle(progress, 'background-position-y', '-' + (12 * level) + 'px');
+ },
+
+ showPhotoLink: function(accountId, link) {
+ var photoLink = document.querySelector('#' + accountId + ' .photoLink');
+ photoLink.setAttribute('href', link);
+ UI.setStyle(photoLink, 'display', 'inline');
+ },
+
+ hidePhotoLink: function(accountId) {
+ var photoLink = document.querySelector('#' + accountId + ' .photoLink');
+ UI.hide(photoLink);
+ },
+
+ showUploadInfo: function(accountId, text) {
+ var uploadInfo = document.querySelector('#' + accountId + ' .uploadInfo');
+ uploadInfo.innerHTML = text;
+ UI.show(uploadInfo);
+ },
+
+ hideUploadInfo: function(accountId) {
+ var uploadInfo = document.querySelector('#' + accountId + ' .uploadInfo');
+ UI.hide(uploadInfo);
+ },
+
+ clearAccounts: function() {
+ $('uploadAccountList').innerHTML = '';
+ },
+
+ addAuthenticatedAccount: function(site, userId) {
+ var template = $('accountItemTemplate').innerHTML;
+
+ // Replace i18n message
+ template = template.replace(/\$\{accountId\}/gi, site + '_' + userId);
+ var shareToText = chrome.i18n.getMessage('share_to');
+ template = template.replace(/\$\{accountName\}/gi,
+ shareToText + ' ' + Account.getUser(site, userId)['name']);
+ template = template.replace('${site}', site);
+ template = template.replace('${userId}', userId);
+ template = template.replace(/\$\{deletionTitle\}/gi,
+ chrome.i18n.getMessage('deletion_title'));
+ template = template.replace(/\$\{photoLinkText\}/gi,
+ chrome.i18n.getMessage('photo_link_text'));
+ template = template.replace(/\$\{progressInfo\}/gi,
+ chrome.i18n.getMessage('progress_info'));
+
+ // At most show 3 authenticated users
+ var uploadAccountList = $('uploadAccountList');
+ var accountsNumber = uploadAccountList.childElementCount;
+ if (accountsNumber == 2) {
+ uploadAccountList.removeChild(uploadAccountList.lastElementChild);
+ }
+ uploadAccountList.innerHTML = template + uploadAccountList.innerHTML;
+
+ $('accountName').addEventListener('click', function(e) {
+ UploadUI.upload(site, userId);
+ });
+ $('deleteBtn').addEventListener('click', function(e) {
+ e.stopPropagation();
+ UploadUI.deleteAccountItem(site + '_' + userId);
+ });
+
+ UploadUI.updateShareToOtherAccountText(site);
+ },
+
+ deleteAccountItem: function(accountId, noConfirm) {
+ if (UploadUI.uploading && !noConfirm)
+ return;
+ var confirmText = chrome.i18n.getMessage('account_deletion_confirm');
+ if (noConfirm || confirm(confirmText)) {
+ $('uploadAccountList').removeChild($(accountId));
+
+ // Clear localStorage
+ var site = accountId.split('_')[0];
+ var userId = accountId.split('_')[1];
+ Account.removeUser(site, userId);
+ UploadUI.updateShareToOtherAccountText(site);
+ }
+ },
+
+ upload: function(siteId, userId) {
+ if (UploadUI.uploading)
+ return;
+
+ // Initialize UI
+ var accountId = siteId + '_' + userId;
+ UploadUI.hideErrorInfo();
+ UploadUI.hideUploadInfo(accountId);
+ UploadUI.hidePhotoLink(accountId);
+ if (!UploadUI.validatePhotoDescription(siteId))
+ return;
+ var caption = $('imageCaption').value;
+
+ // Get ready for upload image.
+ photoshop.draw();
+ UploadUI.setUploading(true);
+ UploadUI.showProgressBar(accountId);
+
+ var site = UploadUI.getSiteObject(siteId);
+ var user = Account.getUser(siteId, userId);
+ var imageData = UploadUI.getImageData();
+ var infoText;
+
+ var callback = function(result, photoIdOrMessage) {
+ if (result == 'success') {
+ infoText = chrome.i18n.getMessage('get_photo_link');
+ UploadUI.showUploadInfo(accountId, infoText);
+ site.getPhotoLink(user, photoIdOrMessage, function(photoLinkResult,
+ photoLinkOrMessage) {
+ if (photoLinkResult == 'success') {
+ UploadUI.setUploading(false);
+ UploadUI.hideUploadInfo(accountId);
+ UploadUI.showPhotoLink(accountId, photoLinkOrMessage);
+ } else {
+ UploadUI.showErrorInfo(photoLinkOrMessage);
+ }
+ });
+ } else {
+ if (photoIdOrMessage == 'bad_access_token' ||
+ photoIdOrMessage == 'invalid_album_id') {
+ Account.removeUser(site.siteId, site.currentUserId);
+ UploadUI.deleteAccountItem(accountId, true);
+ UploadUI.getAccessToken(siteId);
+ }
+ UploadUI.setUploading(false);
+ UploadUI.hideProgressBar(accountId);
+ UploadUI.showErrorInfo(chrome.i18n.getMessage(photoIdOrMessage));
+ }
+ UploadUI.hideProgressBar(accountId);
+ };
+
+ if (user) {
+ site.currentUserId = user.id;
+ site.upload(user, caption, imageData, callback);
+ } else {
+ UploadUI.getAccessToken(siteId);
+ }
+ },
+
+ getAccessToken: function(siteId) {
+ var site = UploadUI.getSiteObject(siteId);
+ var accessTokenCallback = function(result, userOrMessage) {
+ if (result == 'success') {
+ UploadUI.getUserInfo(siteId, userOrMessage);
+ } else {
+ // Show error information according to error reason
+ UploadUI.showErrorInfo(chrome.i18n.getMessage(userOrMessage));
+ UploadUI.hideAuthenticationProgress();
+ }
+ };
+
+ site.getAccessToken(accessTokenCallback);
+ },
+
+ getUserInfo: function(siteId, user) {
+ var site = UploadUI.getSiteObject(siteId);
+ site.getUserInfo(user, function(result, userOrMessage) {
+ if (result == 'success') {
+ var userId = user.id;
+ // Check if the authenticated user is added.
+ if (!Account.getUser(siteId, userId)) {
+ site.currentUserId = userId;
+ Account.addUser(siteId, user);
+ UploadUI.addAuthenticatedAccount(siteId, userId);
+ }
+ UploadUI.upload(siteId, userId);
+ } else {
+ var msg = chrome.i18n.getMessage(userOrMessage);
+ UploadUI.showErrorInfo(msg);
+ }
+ UploadUI.hideAuthenticationProgress();
+ });
+ },
+
+ getImageData: function() {
+ var dataUrl = $('canvas').toDataURL('image/png');
+ var imageDataIndex = dataUrl.indexOf('data:image/png;base64,');
+ if (imageDataIndex != 0) {
+ return;
+ }
+
+ // Decode to binary data
+ return atob(dataUrl.substr(imageDataIndex + 22));
+ },
+
+ saveImage: function() {
+ $('canvas').toBlob(function(blob) {
+ console.log(chrome.extension.getBackgroundPage());
+ saveAs(blob, chrome.extension.getBackgroundPage().screenshot.screenshotName+".png");
+ });
+ }
+};
+
+(function() {
+// Cache tab id of edit page, so that we can get tab focus after getting access
+// token.
+var tabIdOfEditPage;
+chrome.tabs.getSelected(null, function(tab) {
+ tabIdOfEditPage = tab.id;
+});
+
+function selectTab(tabId) {
+ chrome.tabs.update(tabId, {
+ selected: true
+ });
+}
+
+function closeTab(tabId) {
+ chrome.tabs.remove(tabId);
+}
+
+function parseAccessToken(senderId, url, siteId) {
+ var sites = UploadUI.sites;
+ for (var id in sites) {
+ var site = sites[id];
+ if ((siteId && id == siteId) || site.isRedirectUrl(url)) {
+ selectTab(tabIdOfEditPage);
+ closeTab(senderId);
+ site.parseAccessToken(url);
+ return true;
+ }
+ }
+ return false;
+}
+
+chrome.extension.onMessage.addListener(function(request, sender) {
+ switch (request.msg) {
+ case 'url_for_access_token':
+ parseAccessToken(sender.tab.id, request.url, request.siteId);
+ break;
+ }
+});
+})();