<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:thr="http://purl.org/syndication/thread/1.0">
  <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html" />
  <link rel="self" type="application/atom+xml" href="http://www.insideria.com/atom.xml" />
  <id>tag:www.insideria.com,2009://34/tag:www.insideria.com,2009://34.35633-</id>
  <updated>2009-11-16T15:11:06Z</updated>
  <title>Comments for Mimicking Twitterfall&#39;s Short URL Replacement (http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html)</title>
  <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>
  <entry>
    <id>tag:www.insideria.com,2009://34.35633</id>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blogs.oreilly.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=34/entry_id=35633" title="Mimicking Twitterfall&amp;#39;s Short URL Replacement" />
    <published>2009-03-18T01:48:22Z</published>
    <updated>2009-03-24T17:05:09Z</updated>
    <title>Mimicking Twitterfall&#39;s Short URL Replacement</title>
    <summary>Since I discovered Twitterfall.com, I&apos;ve become addicted to the site&apos;s constant stream of Twitter updates. The site works on a basic premise. Enter few search terms, and a &apos;waterfall&apos; of matching tweets will slowly scroll down the screen. It is...</summary>
    <author>
      <name>Raymond Camden</name>
      <uri>http://www.coldfusionjedi.com</uri>
    </author>
    
    <category term="Blogs" />
    
    <content type="html" xml:lang="en" xml:base="http://www.insideria.com/">
      <![CDATA[Since I discovered <a href="http://www.twitterfall.com">Twitterfall.com</a>, I've become addicted to the site's constant stream of Twitter updates. The site works on a basic premise. Enter  few search terms, and a 'waterfall' of matching tweets will slowly scroll down the screen. It is a great way to discovered relevant content from folks outside your normal audience. I use it to monitor both jQuery and ColdFusion and I was really surprised by what I've seen. Even the dupes are interesting. It's fun to see folks RT the same tweet over and over again like a wave of duplicity. 
<p/>
While using Twitterfall, I noticed something pretty cool. Due to the size limitations of Twitter, most folks will use a "Short URL" service (like tinyurl.com) to post links. The problem with this is that it is impossible to tell where these links will take you. I noticed, though, that when I moused over these links in Twitterfall, they actually changed to their full version. 
<p/>
I opened up Firebug and did some digging and noticed that these replacements were being done serverside. With that in mind I decided to see if i could build my own version of this code with jQuery.
<p/>
I first took a deeper look at the content loaded into Twitterfall. I noticed that every URL that supported replacements used a particular class. I also noticed that not all of the short urls used this class. I figured then that Twitterfall was only replacing links for short url services that had an API. I think it is fair to assume then that their server side code is simply looking for certain types of URLs and then adding the class on the fly. For my demo I decided to simply do this manually:
<p/>
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>

&lt;div id="<span class="quote">content</span>"&gt;
&lt;p&gt;
This is a <span class="category2">url</span>: &lt;a href="<span class="quote">http://tinyurl.com/c9kzb4</span>" <span class="category1">class</span>="<span class="quote">surl</span>"&gt;http:<span class="linecomment">//tinyurl.com/c9kzb4&lt;/a&gt; with a </span>
few tests: &lt;a href="<span class="quote">http://tinyurl.com/c9gtw8</span>" <span class="category1">class</span>="<span class="quote">surl</span>"&gt;http:<span class="linecomment">//tinyurl.com/c9gtw8&lt;/a&gt; Some non &lt;a href="http://www.cnn.com"&gt;short&lt;/a&gt; urls as &lt;a href="http://www.yahoo.com"&gt;well&lt;/a&gt;.</span>
&lt;/p&gt;

&lt;p&gt;
A second paragraph <span class="category1">with</span> &lt;a href="<span class="quote">http://snurl.com/dyw9f</span>" <span class="category1">class</span>="<span class="quote">surl</span>"&gt;http:<span class="linecomment">//snurl.com/dyw9f&lt;/a&gt; tests. </span>
&lt;/p&gt;
&lt;/div&gt;</pre>
</code>

</div></div>
<p/>
The HTML above contains two paragraphs. The first paragraph has a few links. Two of them use tinyurl.com and have a class of surl. The second paragraph has a link to snurl.com and also uses surl.
<p/>
My first task is to pick up on the links that have the surl class:
<p/>
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>

$(document).ready(<span class="category1">function</span>() {
 	$("<span class="quote">.surl</span>").mouseover(rewriteURL)
});</pre>
</code>

</div></div>
<p/>
Nothing too complex here. My selector grabs all the items with the surl class and assigns an event handler for the mouseover event. The rewriteURL function is where the magic happens:
<p/>
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">function</span> rewriteURL(e) {
 	<span class="category1">var</span> <span class="category2">url</span> = e.<span class="category2">target</span>.href
 	$.<span class="category2">get</span>("<span class="quote">getrealurl.cfm</span>",{href:<span class="category2">url</span>},<span class="category1">function</span>(<span class="category2">data</span>) {
  		<span class="linecomment">//change text</span>
  		$(e.<span class="category2">target</span>).<span class="category2">html</span>(<span class="category2">data</span>)
  		$(e.<span class="category2">target</span>).unbind("<span class="quote">mouseover</span>")
  	});
}</pre>
</code>

</div></div>
<p/>
Ok, so line by line, I begin by grabbing the URL of the link the user just moused over. I take that URL and pass it to my server side code. The result will be the full URL, so I can simply change the HTML of the link to the new value. At this point the short url will be rewritten as the full url (details forthcoming in the ColdFusion code in a minute) so there is no point in running the code again. The unbind call will remove the mouseover event from the link so it won't run again.
<p/>
That's it. Well, on the client. The server is a bit more complex. My example works with tinyurl and snurl, both short url services that have basic APIs. I wrote up simple UDFs to handle the translation, and then used them like so:
<p/>
 <div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
&lt;cfsetting enablecfoutputonly="<span class="quote">true</span>"&gt;

&lt;cfparam <span class="category2">name</span>="<span class="quote">url.href</span>" <span class="category1">default</span>="<span class="quote"></span>"&gt;

&lt;!---
&lt;cfoutput&gt;i got #url.href#&lt;/cfoutput&gt;
---&gt;

&lt;cffunction <span class="category2">name</span>="<span class="quote">getSnurlOriginal</span>" output="<span class="quote">false</span>" returnType="<span class="quote">string</span>"&gt;
	&lt;cfargument <span class="category2">name</span>="<span class="quote">snurl</span>" <span class="category2">type</span>="<span class="quote">string</span>" required="<span class="quote">true</span>"&gt;
	&lt;cfset <span class="category1">var</span> result = "<span class="quote"></span>"&gt;
	&lt;cfset <span class="category1">var</span> resp = "<span class="quote"></span>"&gt;

	&lt;cfhttp <span class="category2">url</span>="<span class="quote">http://snipurl.com/site/getsnipdetails</span>" <span class="category1">method</span>="<span class="quote">post</span>" result="<span class="quote">result</span>"&gt;
		&lt;cfhttpparam <span class="category2">type</span>="<span class="quote">formfield</span>" <span class="category2">name</span>="<span class="quote">snipid</span>" value="<span class="quote">#arguments.snurl#</span>"&gt;
		&lt;cfhttpparam <span class="category2">type</span>="<span class="quote">formfield</span>" <span class="category2">name</span>="<span class="quote">snipuser</span>" value="<span class="quote">cfjedimaster</span>"&gt;
		&lt;cfhttpparam <span class="category2">type</span>="<span class="quote">formfield</span>" <span class="category2">name</span>="<span class="quote">snipapi</span>" value="<span class="quote">03fb4bdaebbc55dc5ab2c16dcc46d9e1</span>"&gt;
	&lt;/cfhttp&gt;
	&lt;cfset resp = xmlParse(result.fileContent)&gt;
	&lt;cfset realUrl = urlDecode(resp.snip.<span class="category2">url</span>.xmltext)&gt;

	&lt;cfreturn realUrl&gt;
&lt;/cffunction&gt;

&lt;cffunction <span class="category2">name</span>="<span class="quote">getTinyOriginal</span>" output="<span class="quote">false</span>" returnType="<span class="quote">string</span>"&gt;
	&lt;cfargument <span class="category2">name</span>="<span class="quote">turl</span>" <span class="category2">type</span>="<span class="quote">string</span>" required="<span class="quote">true</span>"&gt;
	&lt;cfset <span class="category1">var</span> result = "<span class="quote"></span>"&gt;
	&lt;cfset <span class="category1">var</span> match = "<span class="quote"></span>"&gt;
	&lt;cfset <span class="category1">var</span> mylink = "<span class="quote"></span>"&gt;

	&lt;cfhttp <span class="category2">url</span>="<span class="quote">http://preview.tinyurl.com/#listLast(arguments.turl,</span>"/"<span class="quote">)#</span>" result="<span class="quote">result</span>"&gt;
	&lt;cfset result = result.fileContent&gt;

	&lt;!--- look <span class="category1">for</span> redirecturl ---&gt;
	&lt;cfset match = reFindNoCase("<span class="quote">redirecturl</span>""<span class="quote"> href=</span>""<span class="quote">(.*?)</span>""<span class="quote"></span>", result,1, 1)&gt;
	&lt;cfset mylink = mid(result, match.pos[2], match.len[2])&gt;
	&lt;cfreturn mylink&gt;
&lt;/cffunction&gt;

&lt;cfif findNoCase("<span class="quote">snurl.com</span>", <span class="category2">url</span>.href)&gt;

	&lt;cfoutput&gt;#getSnurlOriginal(<span class="category2">url</span>.href)#&lt;/cfoutput&gt;

&lt;cfelseif findNoCase("<span class="quote">tinyurl.com</span>", <span class="category2">url</span>.href)&gt;

	&lt;cfoutput&gt;#getTinyOriginal(<span class="category2">url</span>.href)#&lt;/cfoutput&gt;

&lt;cfelse&gt;

	&lt;cfoutput&gt;#url.href#&lt;/cfoutput&gt;

&lt;/cfif&gt;</pre>
</code>

</div></div>
<p/>
The web site address to be modified is sent in via the URL scope as the HREF value. Notice I have some code commented on top: i got #url.href#. This was my original code when I was working on the client side. I used it as a quick way to see if my jQuery code was working correctly. Immediately after this are two UDFs. You don't need to worry about them too much, but they handle the reverse lookup for Snurl and TinyURL. The real logic then is the checks to see which service is being used. If we find snurl.com, then use that UDF to translate the UDF. If we see tinyurl.com, use that UDF. Lastly we simply return the URL unchanged at all if we don't recognize it at all.
<p/>
You can see this in action here: <a href="http://www.coldfusionjedi.com/demos/surlrewrite/test.html">http://www.coldfusionjedi.com/demos/surlrewrite/test.html</a>]]>
      
    </content>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.35633-comment:2055403</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.35633" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html#comment-2055403" />
    <title>Comment from Barney on 2009-03-17</title>
    <author>
        <name>Barney</name>
        <uri>http://www.barneyb.com/</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.barneyb.com/">
        <![CDATA[<p>CFHTTP will let you support any service that does a server-side redirect, API or not.  Just hit the short URL with redirect="false" and grab the Location header of the response.  Works for tinyurl, snurl, and is.gd at least.  I didn't try any others.</p>

<p>Obviously an API is a conceptually cleaner solution, but I'm pretty sure HTTP is a sufficiently clean API for this task, and it lets you handle all services in the same way, without having to code against multiple APIs.</p>]]>
    </content>
    <published>2009-03-18T03:54:22Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.35633-comment:2055430</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.35633" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html#comment-2055430" />
    <title>Comment from Raymond Camden on 2009-03-18</title>
    <author>
        <name>Raymond Camden</name>
        <uri>http://www.coldfusionjedi.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.coldfusionjedi.com">
        <![CDATA[<p>Barney - good point. When I was looking at Twitterfall and noticed that only some of their SURLs did the rewrite, I just assumed that was the logic they used (formal api - do the rewrite).</p>]]>
    </content>
    <published>2009-03-18T11:44:55Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.35633-comment:2055470</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.35633" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html#comment-2055470" />
    <title>Comment from mbdof on 2009-03-18</title>
    <author>
        <name>mbdof</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>Twitterfall is designed, written and maintained by two 2nd year CS students @ York University in the UK, see Daily Telegraph article on Twitter section of the Telegraph website!</p>]]>
    </content>
    <published>2009-03-18T19:40:31Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.35633-comment:2055792</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.35633" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html#comment-2055792" />
    <title>Comment from Troy on 2009-03-23</title>
    <author>
        <name>Troy</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>Ray, could you make use of <a href="http://long.to">http://long.to</a> as a way to resolve the short URLs to their full version?</p>]]>
    </content>
    <published>2009-03-23T20:11:20Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.35633-comment:2055794</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.35633" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/mimicing-twitterfalls-short-ur.html#comment-2055794" />
    <title>Comment from Raymond Camden on 2009-03-23</title>
    <author>
        <name>Raymond Camden</name>
        <uri>http://www.coldfusionjedi.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.coldfusionjedi.com">
        <![CDATA[<p>Nice, I had no idea about that service Troy. Yes, it COULD be used. Well, I'm assuming it does what it says it does. ;)</p>]]>
    </content>
    <published>2009-03-23T20:22:46Z</published>
  </entry>

</feed
