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  * A file uploader class for SpazCore 
 15  */
 16 
 17 /**
 18  * Events used by this library 
 19  */
 20 if (!sc.events) { sc.events = {}; }
 21 sc.events.fileUploadStart	= 'fileUploadStart';
 22 sc.events.fileUploadSuccess	= 'fileUploadSuccess';
 23 sc.events.fileUploadFailure	= 'fileUploadFailure';
 24 
 25 
 26 
 27 /**
 28  * A File uploader class
 29  * 
 30  * opts = {
 31  *   api:'',
 32  *   startEvent:'',
 33  *   successEvent:'',
 34  *   failureEvent:'',
 35  *   eventTarget:DOMElement
 36  * } 
 37  * @constructor
 38  */
 39 function SpazFileUploader(opts) {
 40 
 41 	if (!opts) { opts = {}; }
 42 		
 43 	if (opts.api) {
 44 		this.setAPI(opts.api);
 45 	}
 46 	this.startEvent   = opts.startEvent   || sc.events.fileUploadStart;
 47 	this.successEvent = opts.successEvent || sc.events.fileUploadSuccess;
 48 	this.failureEvent = opts.failureEvent || sc.events.fileUploadFailure;
 49 	this.eventTarget  = opts.eventTarget  || document;
 50 	this.auth         = opts.auth         || null;
 51 	
 52 	this.apis = this.getAPIs();
 53 
 54 }
 55 
 56 /**
 57  * returns an array of API labels
 58  * @return array 
 59  */
 60 SpazFileUploader.prototype.getAPILabels = function() {
 61 	var labels = [];
 62 	for ( var key in this.getAPIs() ) {
 63 		labels.push(key);
 64 	}
 65 	return labels;
 66 };
 67 
 68 
 69 /**
 70  * This builds the apis hash and returns it. All API stuff is defined inside here
 71  */
 72 SpazFileUploader.prototype.getAPIs = function() {
 73 
 74 	var thisSFU = this;
 75 
 76 	var apis = {
 77 	    'drippic' : {
 78 			'upload_url' : 'http://drippic.com/drippic/upload',
 79 		    'post_url'   : 'http://drippic.com/drippic/upload/tweet',
 80 			'processResult': function(event, apiobj) {
 81 				var loader = event.target;
 82 				
 83 				sch.debug('PROCESSING: EVENT');
 84 				sch.debug(event);
 85 
 86 				var parser=new DOMParser();
 87 				var xmldoc = parser.parseFromString(event.data,"text/xml");
 88 
 89 				var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes;
 90 				if (rspAttr.getNamedItem("stat").nodeValue === 'ok')
 91 				{
 92 					returnobj['mediaurl'] = jQuery(xmldoc).find('mediaurl').text();
 93 				} 
 94 				else
 95 				{
 96 					returnobj['errMsg'] = jQuery(xmldoc).find('error').text();
 97 				}
 98 				sch.debug(returnobj);
 99 				return returnobj;
100 			}
101 		},
102 		'pikchur' : {
103 		    'upload_url' : 'http://api.pikchur.com/simple/upload',
104 		    'post_url' : 'http://api.pikchur.com/simple/uploadAndPost',
105 			'api_key_field': 'api_key', // setting this to non-empty means we MUST set an api key
106 			'processResult': function(event, apiobj) {
107 				var loader = event.target;
108 				
109 				var returnobj = {};
110 
111 				var parser=new DOMParser();
112 				var xmldoc = parser.parseFromString(loader.data,"text/xml");
113 
114 				var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes;
115 				if (rspAttr.getNamedItem("stat").nodeValue === 'ok')
116 				{
117 					returnobj['mediaurl'] = jQuery(xmldoc).find('mediaurl').text();
118 				} 
119 				else
120 				{
121 					returnobj['errAttributes'] = xmldoc.getElementsByTagName("err")[0].attributes;
122 					returnobj['errMsg'] = errAttributes.getNamedItem("msg").nodeValue;
123 				}
124 				sch.debug(returnobj);
125 				return returnobj;
126 			}
127 		},
128 		'yfrog' : {
129 		    'upload_url' : 'http://yfrog.com/api/upload',
130 		    'post_url' : 'http://yfrog.com/api/uploadAndPost',
131 			'processResult': function(event, apiobj) {
132 				var loader = event.target;
133 
134 				var parser=new DOMParser();
135 				var xmldoc = parser.parseFromString(loader.data,"text/xml");
136 
137 				var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes;
138 				if (rspAttr.getNamedItem("stat").nodeValue === 'ok')
139 				{
140 					returnobj['mediaurl'] = jQuery(xmldoc).find('mediaurl').text();
141 				} 
142 				else
143 				{
144 					returnobj['errAttributes'] = xmldoc.getElementsByTagName("err")[0].attributes;
145 					returnobj['errMsg'] = errAttributes.getNamedItem("msg").nodeValue;
146 				}
147 				sch.debug(returnobj);
148 				return returnobj;
149 			}
150 		},
151 	    'twitpic' : {
152 			'upload_url' : 'http://twitpic.com/api/upload',
153 		    'post_url'   : 'http://twitpic.com/api/uploadAndPost',
154 			'processResult': function(event, apiobj) {
155 				var loader = event.target;
156 				
157 				sch.debug('PROCESSING: EVENT');
158 				sch.debug(event);
159 
160 				var parser=new DOMParser();
161 				var xmldoc = parser.parseFromString(event.data,"text/xml");
162 
163 				var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes;
164 				if (rspAttr.getNamedItem("stat").nodeValue === 'ok')
165 				{
166 					returnobj['mediaurl'] = jQuery(xmldoc).find('mediaurl').text();
167 				} 
168 				else
169 				{
170 					returnobj['errAttributes'] = xmldoc.getElementsByTagName("err")[0].attributes;
171 					returnobj['errMsg'] = errAttributes.getNamedItem("msg").nodeValue;
172 				}
173 				sch.debug(returnobj);
174 				return returnobj;
175 			}
176 		},
177 	    'posterous' : {
178 			'upload_url' : 'http://posterous.com/api/upload',
179 		    'post_url'   : 'http://posterous.com/api/uploadAndPost',
180 			'processResult': function(event, apiobj) {
181 				var loader = event.target;
182 				
183 				sch.debug('PROCESSING: EVENT');
184 				sch.debug(event);
185 
186 				var parser=new DOMParser();
187 				var xmldoc = parser.parseFromString(event.data,"text/xml");
188 
189 				var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes;
190 				if (rspAttr.getNamedItem("stat").nodeValue === 'ok')
191 				{
192 					returnobj['mediaurl'] = jQuery(xmldoc).find('mediaurl').text();
193 				} 
194 				else
195 				{
196 					returnobj['errAttributes'] = xmldoc.getElementsByTagName("err")[0].attributes;
197 					returnobj['errMsg'] = errAttributes.getNamedItem("msg").nodeValue;
198 				}
199 				sch.debug(returnobj);
200 				return returnobj;
201 			}
202 		},
203 		'twitgoo' : {
204 			'upload_url' : 'http://twitgoo.com/api/upload',
205 			'post_url'   : 'http://twitgoo.com/api/uploadAndPost',
206 			'processResult': function(event, apiobj) {
207 				var loader = event.target;
208 
209 				var parser=new DOMParser();
210 				var xmldoc = parser.parseFromString(loader.data,"text/xml");
211 
212 				var rspAttr = xmldoc.getElementsByTagName("rsp")[0].attributes;
213 				if (rspAttr.getNamedItem("stat").nodeValue === 'ok')
214 				{
215 					returnobj['mediaurl'] = jQuery(xmldoc).find('mediaurl').text();
216 				} 
217 				else
218 				{
219 					returnobj['errAttributes'] = xmldoc.getElementsByTagName("err")[0].attributes;
220 					returnobj['errMsg'] = errAttributes.getNamedItem("msg").nodeValue;
221 				}
222 				sch.debug(returnobj);
223 				return returnobj;
224 			}
225 		}//,
226 		/*
227 			Not sure if we should continue to support tweetphoto; API is complex
228 		*/
229 		// 'tweetphoto': {
230 		// 	'upload_url' : 'http://tweetphotoapi.com/api/tpapi.svc/upload2',
231 		// 	'api_key_field': 'TPAPIKEY', // this means we need to set the api key
232 		// 	'onBeforeSend' : function(extraParams, api.upload_url, file_url) {
233 		// 	
234 		// 	},
235 		// 	'processResult': function(event, apiobj) {
236 		// 		var loader = event.target;
237 		// 
238 		// 		var parser=new DOMParser();
239 		// 		var xmldoc = parser.parseFromString(loader.data,"text/xml");
240 		// 
241 		// 		if (jQuery(xmldoc).find('Status').text().toLowerCase() === 'ok')
242 		// 		{
243 		// 			var mediaurl = jQuery(xmldoc).find('MediaUrl').text();
244 		// 		} 
245 		// 		else
246 		// 		{
247 		// 			sch.error('There was an error uploading to TweetPhoto')
248 		// 			var errAttributes = xmldoc.getElementsByTagName("err")[0].attributes;
249 		// 			var errMsg = errAttributes.getNamedItem("msg").nodeValue;
250 		// 		}
251 		// 	}	
252 		// }
253 		
254 	};
255 
256 	return apis;
257 
258 };
259 
260 /**
261  * Pass the api you want to use as a string
262  * @param {string} apilabel 
263  */
264 SpazFileUploader.prototype.setAPI = function(apilabel) {
265 	this.api = this.apis[apilabel];
266 };
267 
268 /**
269  * some services require an api key or app identifier. This sets that.
270  * @param {string} api_key
271  */
272 SpazFileUploader.prototype.setAPIKey = function(api_key) {
273 	if (this.api) {
274 		this.api.api_key = api_key;
275 	} else {
276 		sch.error('Must set the API before setting API key');
277 	}
278 };
279 
280 /**
281  * some services require an api key or app identifier. This sets that.
282  * @param {string} api_key
283  */
284 SpazFileUploader.prototype.getAPIKey = function() {
285 	if (this.api) {
286 		return this.api.api_key;
287 	} else {
288 		sch.error('Must set the API before getting API key');
289 		return null;
290 	}
291 };
292 
293 /**
294  * opts = {
295  *   'api':'', // use if not set already
296  *   'username':'xxx',
297  *   'password':'xxx',
298  *   'source':'xxx',
299  *   'message':''
300  *   
301  * } 
302  * 
303  * This uploads a file located at the given file_url. It uses the
304  * sc.helpers.HTTPUploadFile as defined for your given platform.  Events are
305  * raised as set in the constructor on start, success and failure.
306  * 
307  * Note that in the webOS implementation, success events are raised every time
308  * progress is reported, NOT just when completion happens. Check for the
309  * "completed" boolean property in the response object. This may change in the
310  * future.
311  * 
312  * @param {string} post_url  the url we're uploading the file to
313  * @param {string} file_url  the local url of the file we're uploading
314  * @param {object} opts  a set of key/val pairs
315  */
316 SpazFileUploader.prototype.uploadFile = function(post_url, file_url, opts) {
317 
318 	var api, api_key;
319 
320 	var thisSFU = this;
321 
322 	if (opts.api) {
323 		api = this.apis.api;
324 	} else if (this.api) {
325 		api = this.api;
326 	} else {
327 		sch.error('Must set the API before uploading');
328 		return;
329 	}
330 	
331 	var username = opts.username || null;
332 	var password = opts.password || null;
333 	var source   = opts.source   || null;
334 	var message  = opts.message  || null;
335 	
336 	/*
337 		platform opts are for platform-specific options. For now we're using
338 		this because webOS requires the scene controller to call the service
339 		request, so we pass a reference to the scene assistant
340 	*/
341 	var platformOpts = opts.platform || null;
342 
343 	var onStart = opts.onStart || null;
344 
345 	var extraParams = {
346 		"username": username,
347 		"password": password,
348 		"source":   source,
349 		"message":  message
350 	};
351 	
352 	/**
353 	 * if we have an API key field, then we need the api key 
354 	 */
355 	if ( (api.api_key_field) ) {
356 		extraParams[api.api_key_field] = this.getAPIKey();
357 	}
358 
359 	/*
360 		A callback in case we need to massage the data before upload
361 	*/
362 	if (api.onBeforeSend) {
363 		api.onBeforeSend.call(api, extraParams, api.upload_url, file_url);
364 	}
365 	
366 	/*
367 		trigger upload start event
368 	*/
369 	sc.helpers.triggerCustomEvent(thisSFU.startEvent, thisSFU.eventTarget);
370 	
371 	// upload the file
372 	sc.helpers.HTTPUploadFile({
373 			'extra'   : extraParams,
374 			'url'     : post_url,
375 			'file_url': file_url,
376 			'platform': platformOpts,
377 			'auth'    : this.auth
378 		},
379 		function(event) {
380 			sch.debug('UPLOAD SUCCESS, PROCESSING');
381 			/*
382 				For now we're not using the processResult methods, as the 
383 				implementation can vary by platform. For now, process response
384 				externally.
385 			*/
386 			// var data = api.processResult.call(thisSFU, event, api);
387 			// sch.debug(data);
388 			sc.helpers.triggerCustomEvent(thisSFU.successEvent, thisSFU.eventTarget, event);
389 		},
390 		function(event) {
391 			sch.debug('UPLOAD FAILURE, PROCESSING');
392 			/*
393 				For now we're not using the processResult methods, as the 
394 				implementation can vary by platform. For now, process response
395 				externally.
396 			*/
397 			// var data = api.processResult.call(thisSFU, event, api);
398 			// sch.debug(data);
399 			sc.helpers.triggerCustomEvent(thisSFU.failureEvent, thisSFU.eventTarget, event);
400 		}
401 	);
402 };
403 
404 
405 
406 /**
407  * a wrapper for uploadFile that uses the post_url from the API definition 
408  */
409 SpazFileUploader.prototype.uploadAndPost = function(file_url, opts) {
410 	var api;
411 	
412 	if (opts.api) {
413 		api = this.apis.api;
414 	} else if (this.api) {
415 		api = this.api;
416 	} else {
417 		sch.error('Must set the API before uploading');
418 		return;
419 	}
420 	
421 	this.uploadFile(api.post_url, file_url, opts);
422 	
423 };
424 
425 /**
426  * a wrapper for uploadFile that uses the upload_url from the API definition 
427  */
428 SpazFileUploader.prototype.upload = function(file_url, opts) {
429 	
430 	var api;
431 	
432 	if (opts.api) {
433 		api = this.apis.api;
434 	} else if (this.api) {
435 		api = this.api;
436 	} else {
437 		sch.error('Must set the API before uploading');
438 		return;
439 	}
440 	
441 	this.uploadFile(api.upload_url, file_url, opts);
442 	
443 };
444 
445