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, jQuery; 11 12 /** 13 * A library to do url shortening 14 */ 15 16 /** 17 * Constants to refer to services 18 */ 19 /** 20 * @constant 21 */ 22 var SPAZCORE_SHORTURL_SERVICE_SHORTIE = 'short.ie'; 23 /** 24 * @constant 25 */ 26 var SPAZCORE_SHORTURL_SERVICE_ISGD = 'is.gd'; 27 /** 28 * @constant 29 */ 30 var SPAZCORE_SHORTURL_SERVICE_BITLY = 'bit.ly'; 31 /** 32 * @constant 33 */ 34 var SPAZCORE_SHORTURL_SERVICE_JMP = 'j.mp'; 35 36 /** 37 * @constant 38 */ 39 var SPAZCORE_EXPANDABLE_DOMAINS = [ 40 "bit.ly", 41 "cli.gs", 42 "digg.com", 43 "fb.me", 44 "is.gd", 45 "j.mp", 46 "kl.am", 47 "su.pr", 48 "tinyurl.com", 49 "goo.gl", 50 "307.to", 51 "adjix.com", 52 "b23.ru", 53 "bacn.me", 54 "bloat.me", 55 "budurl.com", 56 "clipurl.us", 57 "cort.as", 58 "dwarfurl.com", 59 "ff.im", 60 "fff.to", 61 "href.in", 62 "idek.net", 63 "korta.nu", 64 "lin.cr", 65 "livesi.de", 66 "ln-s.net", 67 "loopt.us", 68 "lost.in", 69 "memurl.com", 70 "merky.de", 71 "migre.me", 72 "moourl.com", 73 "nanourl.se", 74 "om.ly", 75 "ow.ly", 76 "peaurl.com", 77 "ping.fm", 78 "piurl.com", 79 "plurl.me", 80 "pnt.me", 81 "poprl.com", 82 "post.ly", 83 "rde.me", 84 "reallytinyurl.com", 85 "redir.ec", 86 "retwt.me", 87 "rubyurl.com", 88 "short.ie", 89 "short.to", 90 "smallr.com", 91 "sn.im", 92 "sn.vc", 93 "snipr.com", 94 "snipurl.com", 95 "snurl.com", 96 "tiny.cc", 97 "tinysong.com", 98 "togoto.us", 99 "tr.im", 100 "tra.kz", 101 "trg.li", 102 "twurl.cc", 103 "twurl.nl", 104 "u.mavrev.com", 105 "u.nu", 106 "ur1.ca", 107 "url.az", 108 "url.ie", 109 "urlx.ie", 110 "w34.us", 111 "xrl.us", 112 "yep.it", 113 "zi.ma", 114 "zurl.ws", 115 "chilp.it", 116 "notlong.com", 117 "qlnk.net", 118 "trim.li", 119 "url4.eu" 120 ]; 121 122 123 /** 124 * events raised here 125 */ 126 if (!sc.events) { sc.events = {}; } 127 sc.events.newShortURLSuccess = 'newShortURLSuccess'; 128 sc.events.newShortURLFailure = 'newShortURLFailure'; 129 sc.events.newExpandURLSuccess = 'recoverLongURLSuccess'; 130 sc.events.newExpandURLFailure = 'recoverLongURLFailure'; 131 132 133 /** 134 * Constructor 135 * @param {string} service the name of a service. Preferrably one of the SPAZCORE_SHORTURL_SERVICE_* constants 136 * @class SpazShortURL 137 * @constructor 138 */ 139 function SpazShortURL(service) { 140 141 this.api = this.getAPIObj(service); 142 143 144 this.expanded_cache = {}; 145 146 } 147 148 SpazShortURL.prototype.getAPIObj = function(service) { 149 150 var apis = {}; 151 152 apis[SPAZCORE_SHORTURL_SERVICE_BITLY] = { 153 'url' : 'http://bit.ly/api', 154 'getData' : function(longurl, opts){ 155 156 /* 157 use the api if we're doing multiple URLs 158 */ 159 if (sc.helpers.isArray(longurl)) { 160 apis[SPAZCORE_SHORTURL_SERVICE_BITLY].processing_multiple = true; 161 apis[SPAZCORE_SHORTURL_SERVICE_BITLY].url = 'http://api.bit.ly/shorten'; 162 opts.longUrl = longurl; 163 return opts; 164 } else { 165 apis[SPAZCORE_SHORTURL_SERVICE_BITLY].processing_multiple = false; 166 return { 'url':longurl }; 167 } 168 }, 169 'processResult' : function(data) { 170 if (apis[SPAZCORE_SHORTURL_SERVICE_BITLY].processing_multiple === true) { 171 var result = sc.helpers.deJSON(data); 172 var rs = {}; 173 for (var i in result.results) { 174 rs[i] = result.results[i].shortUrl; 175 } 176 return rs; 177 } else { 178 return data; 179 } 180 } 181 182 }; 183 184 apis[SPAZCORE_SHORTURL_SERVICE_JMP] = { 185 'url' : 'http://j.mp/api', 186 'getData' : function(longurl, opts){ 187 188 /* 189 use the api if we're doing multiple URLs 190 */ 191 if (sc.helpers.isArray(longurl)) { 192 apis[SPAZCORE_SHORTURL_SERVICE_JMP].processing_multiple = true; 193 apis[SPAZCORE_SHORTURL_SERVICE_JMP].url = 'http://api.j.mp/shorten'; 194 opts.longUrl = longurl; 195 return opts; 196 } else { 197 apis[SPAZCORE_SHORTURL_SERVICE_JMP].processing_multiple = false; 198 return { 'url':longurl }; 199 } 200 }, 201 'processResult' : function(data) { 202 if (apis[SPAZCORE_SHORTURL_SERVICE_JMP].processing_multiple === true) { 203 var result = sc.helpers.deJSON(data); 204 var rs = {}; 205 for (var i in result.results) { 206 rs[i] = result.results[i].shortUrl; 207 } 208 return rs; 209 } else { 210 return data; 211 } 212 } 213 214 }; 215 216 apis[SPAZCORE_SHORTURL_SERVICE_SHORTIE] = { 217 'url' : 'http://short.ie/api?', 218 'getData' : function(longurl, opts){ 219 220 if (longurl.match(/ /gi)) { 221 longurl = longurl.replace(/ /gi, '%20'); 222 } 223 224 var shortie = { 225 orig: longurl, 226 url: longurl, 227 email: '', 228 'private': 'false', 229 format: 'rest' 230 }; 231 return shortie; 232 } 233 }; 234 235 apis[SPAZCORE_SHORTURL_SERVICE_ISGD] = { 236 'url' : 'http://is.gd/api.php', 237 'getData' : function(longurl, opts) { 238 return { 'longurl':longurl }; 239 } 240 }; 241 242 return apis[service]; 243 }; 244 245 246 /** 247 * shortens a URL by making an ajax call 248 * @param {string} longurl 249 * @param {object} opts right now opts.event_target (a DOMelement) and opts.apiopts (passed to api's getData() call) are supported 250 */ 251 SpazShortURL.prototype.shorten = function(longurl, opts) { 252 253 var shortener = this; 254 255 if (!opts) { opts = {}; } 256 257 /* 258 set defaults if needed 259 */ 260 opts.event_target = opts.event_target || document; 261 opts.apiopts = opts.apiopts || null; 262 263 /* 264 we call getData now in case it needs to override anything 265 */ 266 var apidata = this.api.getData(longurl, opts.apiopts); 267 268 if (sc.helpers.getMojoURL) { 269 this.api.url = sc.helpers.getMojoURL(this.api.url); 270 } 271 272 273 var xhr = jQuery.ajax({ 274 'traditional':true, // so we don't use square brackets on arrays in data. Bit.ly doesn't like it 275 'dataType':'text', 276 complete:function(xhr, rstr) { 277 }, 278 'error':function(xhr, msg, exc) { 279 sc.helpers.dump(shortener.api.url + ' error:'+msg); 280 281 var errobj = {'url':shortener.api.url, 'xhr':null, 'msg':null}; 282 283 if (xhr) { 284 errobj.xhr = xhr; 285 sc.helpers.error("Error:"+xhr.status+" from "+ shortener.api.url); 286 } else { 287 sc.helpers.error("Error:Unknown from "+ shortener.api.url); 288 errobj.msg = 'Unknown Error'; 289 } 290 shortener._onShortenResponseFailure(errobj, opts.event_target); 291 }, 292 success:function(data) { 293 // var shorturl = trim(data); 294 var return_data = {}; 295 if (shortener.api.processResult) { 296 return_data = shortener.api.processResult(data); 297 } else { 298 return_data = { 299 'shorturl':data, 300 'longurl' :longurl 301 }; 302 } 303 sch.error(return_data); 304 shortener._onShortenResponseSuccess(return_data, opts.event_target); 305 }, 306 'type':"POST", 307 'url' :this.api.url, 308 'data':apidata 309 }); 310 311 }; 312 313 SpazShortURL.prototype._onShortenResponseSuccess = function(data, target) { 314 sc.helpers.triggerCustomEvent(sc.events.newShortURLSuccess, target, data); 315 }; 316 SpazShortURL.prototype._onShortenResponseFailure = function(errobj, target) { 317 sc.helpers.triggerCustomEvent(sc.events.newShortURLFailure, target, errobj); 318 }; 319 320 /** 321 * @TODO 322 */ 323 SpazShortURL.prototype.expand = function(shorturl, opts) { 324 325 var shortener = this; 326 var longurl; 327 328 if (!opts) { 329 opts = {}; 330 } 331 332 opts.event_target = opts.event_target || document; 333 334 /* 335 Do a lookup in the cache first 336 */ 337 if ( (longurl = this.getExpandedURLFromCache()) ) { 338 shortener._onExpandResponseSuccess({ 339 'shorturl':shorturl, 340 'longurl' :longurl 341 }, 342 opts.event_target 343 ); 344 return; 345 } 346 347 /* 348 if not cached, do query to look it up 349 */ 350 var xhr = jQuery.ajax({ 351 'dataType':'text', 352 complete:function(xhr, rstr) { 353 }, 354 'error':function(xhr, msg, exc) { 355 sc.helpers.dump(this.url + ' error:'+msg); 356 357 var errobj = {'url':this.url, 'xhr':null, 'msg':null}; 358 359 if (xhr) { 360 errobj.xhr = xhr; 361 sc.helpers.dump("Error:"+xhr.status+" from "+ this.url); 362 } else { 363 sc.helpers.dump("Error:Unknown from "+ this.url); 364 errobj.msg = 'Unknown Error'; 365 } 366 shortener._onExpandResponseFailure(errobj, opts.event_target); 367 }, 368 success:function(data) { 369 // var shorturl = trim(data); 370 data = sc.helpers.deJSON(data); 371 var longurl = data[shorturl]; 372 373 /* 374 save it to cache 375 */ 376 shortener.saveExpandedURLToCache(shorturl, longurl); 377 378 shortener._onExpandResponseSuccess({ 379 'shorturl':shorturl, 380 'longurl' :longurl 381 }, 382 opts.event_target 383 ); 384 }, 385 beforeSend:function(xhr) {}, 386 type:"GET", 387 url :'http://longurlplease.appspot.com/api/v1.1', 388 data:{ 'q':shorturl } 389 }); 390 }; 391 392 /** 393 * @TODO 394 */ 395 SpazShortURL.prototype._onExpandResponseSuccess = function(data, target) { 396 sc.helpers.triggerCustomEvent(sc.events.newExpandURLSuccess, target, data); 397 }; 398 399 /** 400 * @TODO 401 */ 402 SpazShortURL.prototype._onExpandResponseFailure = function(errobj, target) { 403 sc.helpers.triggerCustomEvent(sc.events.newExpandURLFailure, target, errobj); 404 }; 405 406 407 SpazShortURL.prototype.findExpandableURLs = function(str) { 408 var x, i, matches = [], re_matches, key, thisdomain, thisregex, regexes = []; 409 410 for (i=0; i < SPAZCORE_EXPANDABLE_DOMAINS.length; i++) { 411 thisdomain = SPAZCORE_EXPANDABLE_DOMAINS[i]; 412 if (thisdomain == 'ff.im') { 413 regexes.push(new RegExp("http://"+thisdomain+"/(-?[a-zA-Z0-9]+)", "gi")); 414 } else { 415 regexes.push(new RegExp("http://"+thisdomain+"/([a-zA-Z0-9]+)", "gi")); 416 } 417 418 }; 419 420 for (i=0; i < regexes.length; i++) { 421 thisregex = regexes[i]; 422 sch.dump("looking for "+thisregex+ " in '"+str+"'"); 423 while( (re_matches = thisregex.exec(sch.trim(str))) != null) { 424 matches.push(re_matches[0]); 425 } 426 }; 427 428 sch.dump(matches); 429 430 if (matches.length > 0) { 431 return matches; 432 } else { 433 return null; 434 } 435 436 }; 437 438 439 SpazShortURL.prototype.expandURLs = function(urls, target) { 440 for (var i=0; i < urls.length; i++) { 441 var thisurl = urls[i]; 442 sch.dump('expanding '+thisurl); 443 this.expand(thisurl, { 'event_target':target }); 444 }; 445 }; 446 447 448 449 /** 450 * @param {string} str the string to replace the URLs in 451 * @param {string} shorturl 452 * @param {string} longurl 453 */ 454 SpazShortURL.prototype.replaceExpandableURL = function(str, shorturl, longurl) { 455 str = str.replace(shorturl, longurl, 'gi'); 456 /* 457 we also expand the non-http://-prefixed versions. Wonder if this is a bad idea, though -- seems 458 possible we could have unexpected consqeuences with this 459 */ 460 str = str.replace(shorturl.replace('http://', ''), longurl.replace('http://', ''), 'gi'); 461 return str; 462 }; 463 464 465 466 SpazShortURL.prototype.getExpandedURLFromCache = function(shortURL) { 467 return this.expanded_cache[shortURL]; 468 }; 469 470 SpazShortURL.prototype.saveExpandedURLToCache = function(shortURL, longURL) { 471 this.expanded_cache[shortURL] = longURL; 472 };