1 /*jslint 2 browser: true, 3 nomen: false, 4 debug: true, 5 forin: true, 6 undef: true, 7 white: false, 8 onevar: false 9 */ 10 var sc, DOMParser, jQuery; 11 12 13 /** 14 * An image uploader library for SpazCore. Probably this will supercede spazfileuploader.js 15 * @param {object} [opts] options hash 16 * @param {object} [opts.auth_obj] A SpazAuth object that's filled with proper authentication info 17 * @param {string} [opts.username] a username, in case we're doing that kind of thing 18 * @param {string} [opts.password] a password, in case we're doing that kind of thing 19 * @param {string} [opts.auth_method] the method of authentication: 'echo' or 'basic'. Default is 'echo' 20 * @param {object} [opts.extra] Extra params to pass in the upload request 21 * @constructor 22 */ 23 var SpazImageUploader = function(opts) { 24 if (opts) { 25 this.setOpts(opts); 26 } 27 }; 28 29 30 /** 31 * this lets us set options after instantiation 32 * @param {object} opts options hash 33 * @param {object} [opts.auth_obj] A SpazAuth object that's filled with proper authentication info 34 * @param {string} [opts.username] a username, in case we're doing that kind of thing 35 * @param {string} [opts.password] a password, in case we're doing that kind of thing 36 * @param {string} [opts.auth_method] the method of authentication: 'echo' or 'basic'. Default is 'echo' 37 * @param {string} [opts.statusnet_api_base] the api base URL for statusnet, if that service is used 38 * @param {object} [opts.extra] Extra params to pass in the upload request 39 */ 40 SpazImageUploader.prototype.setOpts = function(opts) { 41 this.opts = sch.defaults({ 42 'extra':{}, 43 'auth_obj':null, 44 'username':null, 45 'password':null, 46 'auth_method':'echo', // 'echo' or 'basic' 47 'statusnet_api_base':null // only used by statusnet 48 }, opts); 49 }; 50 51 /** 52 * returns an array of labels for the services 53 * @return array 54 */ 55 SpazImageUploader.prototype.getServiceLabels = function() { 56 var labels = []; 57 for(var key in this.services) { 58 labels.push(key); 59 } 60 return labels; 61 }; 62 63 /** 64 * a hash of service objects. Each object has a URL endpoint, a parseResponse callback, and an optional "extra" set of params to pass on upload 65 * parseResponse should return one of these key/val pairs: 66 * - {'url':'http://foo.bar/XXXX'} 67 * - {'error':'Error message'} 68 */ 69 SpazImageUploader.prototype.services = { 70 'drippic' : { 71 'url' : 'http://drippic.com/drippic2/upload', 72 'parseResponse': function(data) { 73 74 var parser=new DOMParser(); 75 xmldoc = parser.parseFromString(data,"text/xml"); 76 77 var status; 78 var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes; 79 status = rspAttr.getNamedItem("stat").nodeValue; 80 81 if (status == 'ok') { 82 var mediaurl = $(xmldoc).find('mediaurl').text(); 83 return {'url':mediaurl}; 84 } else { 85 var errMsg; 86 if (xmldoc.getElementsByTagName("err")[0]) { 87 errMsg = xmldoc.getElementsByTagName("err")[0].childNodes[0].nodeValue; 88 } else { 89 errMsg = xmldoc.getElementsByTagName("error")[0].childNodes[0].nodeValue; 90 } 91 92 sch.error(errMsg); 93 return {'error':errMsg}; 94 } 95 } 96 }, 97 'pikchur' : { 98 'url' : 'http://api.pikchur.com/simple/upload', 99 'extra': { 100 'api_key':'MzTrvEd/uPNjGDabr539FA', 101 'source':'NjMw' 102 }, 103 'parseResponse': function(data) { 104 var parser=new DOMParser(); 105 xmldoc = parser.parseFromString(data,"text/xml"); 106 107 var status; 108 var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes; 109 if (rspAttr.getNamedItem("status")) { 110 status = rspAttr.getNamedItem("status").nodeValue; 111 } else if(rspAttr.getNamedItem("stat")) { 112 status = rspAttr.getNamedItem("stat").nodeValue; 113 } else { 114 status = 'fuck I wish they would use the same goddamn nodenames'; 115 } 116 117 if (status == 'ok') { 118 var mediaurl = $(xmldoc).find('mediaurl').text(); 119 return {'url':mediaurl}; 120 } else { 121 var errAttributes; 122 if (xmldoc.getElementsByTagName("err")[0]) { 123 errAttributes = xmldoc.getElementsByTagName("err")[0].attributes; 124 } else { 125 errAttributes = xmldoc.getElementsByTagName("error")[0].attributes; 126 } 127 128 sch.error(errAttributes); 129 errMsg = errAttributes.getNamedItem("msg").nodeValue; 130 sch.error(errMsg); 131 return {'error':errMsg}; 132 } 133 } 134 }, 135 /* 136 Removed yfrog for now because their oAuth Echo stuff never seems to work. 137 Not sure if it's my code or theirs 138 */ 139 // 'yfrog' : { 140 // 'url' : 'http://yfrog.com/api/xauth_upload', 141 // 'extra': { 142 // 'key':'579HINUYe8d826dd61808f2580cbda7f13433310' 143 // }, 144 // 'parseResponse': function(data) { 145 // 146 // var parser=new DOMParser(); 147 // xmldoc = parser.parseFromString(data,"text/xml"); 148 // 149 // var status; 150 // var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes; 151 // status = rspAttr.getNamedItem("stat").nodeValue; 152 // 153 // if (status == 'ok') { 154 // var mediaurl = $(xmldoc).find('mediaurl').text(); 155 // return {'url':mediaurl}; 156 // } else { 157 // var errAttributes; 158 // if (xmldoc.getElementsByTagName("err")[0]) { 159 // errAttributes = xmldoc.getElementsByTagName("err")[0].attributes; 160 // } else { 161 // errAttributes = xmldoc.getElementsByTagName("error")[0].attributes; 162 // } 163 // 164 // sch.error(errAttributes); 165 // errMsg = errAttributes.getNamedItem("msg").nodeValue; 166 // sch.error(errMsg); 167 // return {'error':errMsg}; 168 // } 169 // 170 // } 171 // }, 172 'twitpic' : { 173 'url' : 'http://api.twitpic.com/2/upload.json', 174 'extra': { 175 'key':'3d8f511397248dc913193a6195c4a018' 176 }, 177 'parseResponse': function(data) { 178 179 if (sch.isString(data)) { 180 data = sch.deJSON(data); 181 } 182 183 if (data.url) { 184 return {'url':data.url}; 185 } else { 186 return {'error':'unknown error'}; 187 } 188 189 } 190 }, 191 'twitgoo' : { 192 'url' : 'http://twitgoo.com/api/upload', 193 'extra': { 194 'format':'xml', 195 'source':'Spaz', 196 'source_url':'http://getspaz.com' 197 }, 198 'parseResponse': function(data) { 199 200 var parser=new DOMParser(); 201 xmldoc = parser.parseFromString(data,"text/xml"); 202 203 var status; 204 var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes; 205 status = rspAttr.getNamedItem("status").nodeValue; 206 207 if (status == 'ok') { 208 var mediaurl = $(xmldoc).find('mediaurl').text(); 209 return {'url':mediaurl}; 210 } else { 211 var errAttributes; 212 if (xmldoc.getElementsByTagName("err")[0]) { 213 errAttributes = xmldoc.getElementsByTagName("err")[0].attributes; 214 } else { 215 errAttributes = xmldoc.getElementsByTagName("error")[0].attributes; 216 } 217 218 sch.error(errAttributes); 219 errMsg = errAttributes.getNamedItem("msg").nodeValue; 220 sch.error(errMsg); 221 return {'error':errMsg}; 222 } 223 224 } 225 }, 226 'identi.ca' : { 227 'url' : 'http://identi.ca/api/statusnet/media/upload', 228 'parseResponse': function(data) { 229 230 var parser=new DOMParser(); 231 xmldoc = parser.parseFromString(data,"text/xml"); 232 233 var status; 234 var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes; 235 status = rspAttr.getNamedItem("stat").nodeValue; 236 237 if (status == 'ok') { 238 var mediaurl = $(xmldoc).find('mediaurl').text(); 239 return {'url':mediaurl}; 240 } else { 241 var errMsg; 242 if (xmldoc.getElementsByTagName("err")[0]) { 243 errMsg = xmldoc.getElementsByTagName("err")[0].childNodes[0].nodeValue; 244 } else { 245 errMsg = xmldoc.getElementsByTagName("error")[0].childNodes[0].nodeValue; 246 } 247 248 sch.error(errMsg); 249 return {'error':errMsg}; 250 } 251 } 252 }, 253 'statusnet' : { 254 'url' : '/statusnet/media/upload', 255 'prepForUpload':function() { 256 if (this.opts.statusnet_api_base) { 257 this.services.statusnet.url = this.opts.statusnet_api_base + this.services.statusnet.url; 258 } else { 259 sch.error('opts.statusnet_api_base must be set to use statusnet uploader service'); 260 } 261 }, 262 'parseResponse':function(data) { 263 var parser=new DOMParser(); 264 xmldoc = parser.parseFromString(data,"text/xml"); 265 266 var status; 267 var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes; 268 status = rspAttr.getNamedItem("stat").nodeValue; 269 270 if (status == 'ok') { 271 var mediaurl = $(xmldoc).find('mediaurl').text(); 272 return {'url':mediaurl}; 273 } else { 274 var errMsg; 275 if (xmldoc.getElementsByTagName("err")[0]) { 276 errMsg = xmldoc.getElementsByTagName("err")[0].childNodes[0].nodeValue; 277 } else { 278 errMsg = xmldoc.getElementsByTagName("error")[0].childNodes[0].nodeValue; 279 } 280 281 sch.error(errMsg); 282 return {'error':errMsg}; 283 } 284 285 } 286 } 287 }; 288 289 /** 290 * Retrieves the auth_header 291 */ 292 SpazImageUploader.prototype.getAuthHeader = function() { 293 294 var opts = sch.defaults({ 295 'getEchoHeaderOpts':{} 296 }, this.opts); 297 298 var auth_header; 299 var user = opts.username; 300 var pass = opts.password; 301 302 if (opts.auth_method === 'echo') { // this is Twitter. hopefully 303 304 var twit = new SpazTwit({'auth':opts.auth_obj}); 305 auth_header = twit.getEchoHeader(opts.getEchoHeaderOpts); 306 307 } else { 308 auth_header = opts.auth_obj.signRequest(); // returns basic auth header 309 } 310 311 sch.error(auth_header); 312 return auth_header; 313 314 }; 315 316 317 /** 318 * this actually does the upload. Well, really it preps the data and uses sc.helpers.HTTPFileUpload 319 */ 320 SpazImageUploader.prototype.upload = function() { 321 322 var opts = sch.defaults({ 323 extra:{} 324 }, this.opts); 325 326 var srvc = this.services[opts.service]; 327 328 if (srvc.prepForUpload) { 329 srvc.prepForUpload.call(this); 330 } 331 332 /* 333 file url 334 */ 335 opts.url = srvc.url; 336 if (srvc.extra) { 337 opts.extra = jQuery.extend(opts.extra, srvc.extra); 338 } 339 340 var onSuccess, rs; 341 if (srvc.parseResponse) { 342 /** @ignore */ 343 onSuccess = function(data) { 344 if (sch.isString(data)) { 345 rs = srvc.parseResponse.call(srvc, data); 346 return opts.onSuccess(rs); 347 } else if (data && data.responseString) { // webOS will return an object, not just the response string 348 rs = srvc.parseResponse.call(srvc, data.responseString); 349 return opts.onSuccess(rs); 350 } else { // I dunno what it is; just pass it to the callback 351 return opts.onSuccess(data); 352 } 353 }; 354 } else { 355 onSuccess = opts.onSuccess; 356 } 357 358 /* 359 get auth stuff 360 */ 361 var auth_header; 362 if (opts.service === 'yfrog') { 363 verify_url = 'https://api.twitter.com/1/account/verify_credentials.xml'; 364 auth_header = this.getAuthHeader({ 365 'getEchoHeaderOpts': { 366 'verify_url':verify_url 367 } 368 }); 369 } else { 370 verify_url = 'https://api.twitter.com/1/account/verify_credentials.json'; 371 auth_header = this.getAuthHeader(); 372 } 373 374 sch.error(auth_header); 375 if (auth_header.indexOf('Basic ') === 0) { 376 377 opts.username = this.opts.auth_obj.getUsername(); 378 opts.password = this.opts.auth_obj.getPassword(); 379 380 } else { 381 opts.headers = { 382 'X-Auth-Service-Provider': verify_url, 383 'X-Verify-Credentials-Authorization':auth_header 384 }; 385 386 } 387 388 sc.helpers.HTTPUploadFile(opts, onSuccess, opts.onFailure); 389 390 };