github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/clients/chrome/clip-it-good/background.html (about) 1 <html> 2 <head> 3 <script type="text/javascript" src="base64.js"></script> 4 <script type="text/javascript" src="jquery-1.4.2.min.js"></script> 5 <script type="text/javascript" src="chrome_ex_oauthsimple.js"></script> 6 <script type="text/javascript" src="chrome_ex_oauth.js"></script> 7 <script type="text/javascript" src="Crypto.js"></script> 8 <script type="text/javascript" src="SHA1.js"></script> 9 10 <script type="text/javascript" charset="utf-8"> 11 12 var OAUTH = ChromeExOAuth.initBackgroundPage({ 13 'request_url' : 'https://www.google.com/accounts/OAuthGetRequestToken', 14 'authorize_url' : 'https://www.google.com/accounts/OAuthAuthorizeToken', 15 'access_url' : 'https://www.google.com/accounts/OAuthGetAccessToken', 16 'consumer_key' : 'anonymous', 17 'consumer_secret' : 'anonymous', 18 'scope' : 'http://picasaweb.google.com/data/', 19 'app_name' : 'Clip It Good: Chrome Extension' 20 }); 21 22 // Constants for various album types. 23 var PICASA = 'picasa'; 24 var CAMLISTORE = 'camlistore'; 25 var ALBUM_TYPE_STRING = { 26 picasa: 'Picasa Web Albums', 27 camlistore: 'Camlistore' 28 }; 29 30 // Preferences 31 var ALBUM_CONFIG = {}; // 'type' -> ('id' -> 'name') 32 var ALBUM_OPTIONS = {}; // 'type' -> ('id' -> optionsDict) 33 34 function loadAlbumConfig() { 35 var newAlbumConfig = localStorage.getItem('config:albums'); 36 if (newAlbumConfig) { 37 ALBUM_CONFIG = $.parseJSON(newAlbumConfig); 38 } 39 40 var newAlbumOptions = localStorage.getItem('config:albumOptions'); 41 if (newAlbumOptions) { 42 ALBUM_OPTIONS = $.parseJSON(newAlbumOptions); 43 } 44 } 45 46 function saveAlbumConfig() { 47 localStorage.setItem('config:albums', JSON.stringify(ALBUM_CONFIG)); 48 localStorage.setItem('config:albumOptions', JSON.stringify(ALBUM_OPTIONS)); 49 } 50 51 // Sort albums by name. 52 function getSortedAlbums(albumIdNameDict) { 53 var albumIdNameArray = []; 54 $.each(albumIdNameDict, function(id, name) { 55 albumIdNameArray.push({'id': id, 'name': name}); 56 }); 57 albumIdNameArray.sort(function(a, b) { 58 if (a['name'] < b['name']) { 59 return -1; 60 } else if (a['name'] > b['name']) { 61 return 1; 62 } else { 63 return 0; 64 } 65 }); 66 return albumIdNameArray; 67 } 68 69 function setupMenus() { 70 loadAlbumConfig(); 71 72 chrome.contextMenus.removeAll(function() { 73 $.each(ALBUM_CONFIG, function(albumType, albumIdNameDict) { 74 chrome.contextMenus.create({ 75 title: ALBUM_TYPE_STRING[albumType], 76 contexts: ['image'] 77 }); 78 chrome.contextMenus.create({ 79 type: 'separator', 80 contexts: ['image'] 81 }); 82 83 $.each(getSortedAlbums(albumIdNameDict), function(index, albumDict) { 84 chrome.contextMenus.create({ 85 title: albumDict.name, 86 contexts: ['image'], 87 onclick: function(data, tab) { 88 return handleMenuClick( 89 albumType, albumDict.name, albumDict.id, data, tab); 90 } 91 }); 92 }); 93 }); 94 }); 95 } 96 97 // Upload actions 98 var ALBUM_TYPE_UPLOAD_FUNC = { 99 100 picasa: function(albumId, albumName, dataSrcUrl, dataBuffer, uploadDone) { 101 var builder = new BlobBuilder(); 102 builder.append(dataBuffer); 103 104 function complete(resp, xhr) { 105 if (!(xhr.status >= 200 && xhr.status <= 299)) { 106 alert('Error: Response status = ' + xhr.status + 107 ', response body = "' + xhr.responseText + '"'); 108 } else { 109 uploadDone(); 110 } 111 } 112 113 OAUTH.authorize(function() { 114 OAUTH.sendSignedRequest( 115 'http://picasaweb.google.com/data/feed/api/' + 116 'user/default/albumid/' + albumId, 117 complete, 118 { 119 method: 'POST', 120 headers: { 121 'Content-Type': 'image/png', 122 'Slug': dataSrcUrl 123 }, 124 parameters: { 125 alt: 'json' 126 }, 127 body: builder.getBlob('image/png') 128 } 129 ); 130 }); 131 }, 132 133 camlistore: function(albumId, albumName, dataSrcUrl, 134 dataBuffer, uploadDone) { 135 var hash = Crypto.SHA1(new Uint8Array(dataBuffer, 0)); 136 var blobRef = 'sha1-' + hash; 137 var options = ALBUM_OPTIONS[CAMLISTORE][albumId]; 138 139 function doUpload(uploadUrl) { 140 // XXX Use real random boundary. 141 var boundary = 'randomboundaryXYZ'; 142 var contentType = 'multipart/form-data; boundary=' + boundary; 143 144 var header = 145 '--' + boundary + '\r\n' + 146 'Content-Type: application/octet-stream\r\n' + 147 'Content-Disposition: form-data; name="' + blobRef + 148 '"; filename="1"\r\n\r\n' 149 var footer = '\r\n--' + boundary + '--\r\n'; 150 151 var builder = new BlobBuilder(); 152 builder.append(header); 153 builder.append(dataBuffer); 154 builder.append(footer); 155 var payload = builder.getBlob(contentType); 156 157 var uploadXhr = new XMLHttpRequest(); 158 uploadXhr.open('POST', uploadUrl, true, 159 options.username, options.password); 160 uploadXhr.onreadystatechange = function() { 161 if (uploadXhr.readyState == XMLHttpRequest.DONE && 162 uploadXhr.status == 200) { 163 // XXX Check for bad response format (not JSON). 164 var responseJson = $.parseJSON(uploadXhr.responseText) 165 166 if (responseJson.received && 167 responseJson.received.length == 1 && 168 responseJson.received[0].blobRef == blobRef) { 169 console.log('Successful upload: ' + blobRef); 170 uploadDone(); 171 return; 172 } 173 174 alert('Camlistore upload response did not verify blob "' + 175 blobRef + '": ' + uploadXhr.responseText); 176 } 177 // XXX: Handle request errors 178 } 179 uploadXhr.setRequestHeader('Content-Type', contentType); 180 uploadXhr.send(payload); 181 } 182 183 var statXhr = new XMLHttpRequest(); 184 statXhr.open('POST', albumId + '/camli/stat', true, 185 options.username, options.password); 186 statXhr.onreadystatechange = function() { 187 if (statXhr.readyState == XMLHttpRequest.DONE && 188 statXhr.status == 200) { 189 // XXX Check for bad response format (not JSON). 190 var responseJson = $.parseJSON(statXhr.responseText); 191 192 if (responseJson.stat && 193 responseJson.stat.length == 1 && 194 responseJson.stat[0].blobRef == blobRef) { 195 console.log('Blob already present: ' + blobRef); 196 uploadDone(); 197 return; 198 } 199 200 var uploadUrl = responseJson.uploadUrl; 201 if (!uploadUrl) { 202 alert('Camlistore stat response missing "uploadUrl": ' + 203 statXhr.responseText); 204 return; 205 } 206 207 doUpload(uploadUrl); 208 } 209 // XXX: Handle request errors 210 } 211 statXhr.setRequestHeader( 212 'Content-Type', 'application/x-www-form-urlencoded'); 213 statXhr.send('camliversion=1&blob1=' + blobRef); 214 } 215 216 }; 217 218 function handleMenuClick(albumType, albumName, albumId, data, tab) { 219 chrome.pageAction.setTitle({ 220 tabId: tab.id, 221 title: 'Clip It Good: Uploading (' + data.srcUrl.substr(0, 100) + ')' 222 }); 223 chrome.pageAction.show(tab.id); 224 225 var img = document.createElement('img'); 226 img.onload = function() { 227 var canvas = document.createElement('canvas'); 228 canvas.width = img.width; 229 canvas.height = img.height; 230 canvas.getContext('2d').drawImage(img, 0, 0); 231 232 var dataUrl = canvas.toDataURL(); 233 var dataUrlAdjusted = dataUrl.replace('data:image/png;base64,', ''); 234 235 var arrayBuffer = Base64.decode(dataUrlAdjusted).buffer; 236 237 function uploadDone() { 238 chrome.pageAction.hide(tab.id); 239 } 240 241 var uploadFunc = ALBUM_TYPE_UPLOAD_FUNC[albumType]; 242 uploadFunc(albumId, albumName, data.srcUrl, arrayBuffer, uploadDone); 243 } // end onload 244 245 img.src = data.srcUrl; 246 } 247 248 $(document).ready( function() { 249 setupMenus(); 250 }); 251 </script> 252 253 </head> 254 <body> 255 </body> 256 </html>