Translate!!

Subscribe in a reader

Monday, November 16, 2009

A Twitter List Powered Fan Page

Buzz It
submit to reddit StumbleUpon

A Twitter List Powered Fan Page

via  

Introduction

Recently, Twitter rolled out a great new feature on their site – lists. You can now create and compile a list of twitter users and make it easier for others to follow all at once.
Also, at the same time, they expanded their API to include list management functionality. This allows us to use these new tools to create a widget that flips lists the other way around – a fan page you can put in your sidebar, that allows your visitors to fill in their twitter name and join a specially crafted fan list in your twitter account.
So download the example files and lets start coding!

Step 1 – XHTML

As usual, we start with the XHTML. As the widget is entirely AJAX based, this is the only code that you will need to include directly into your site. The rest is fetched asynchronously.

demo.html

<div id="fanPage">

<div class="title">

<a class="fanPageLink" href="http://twitter.com" title="Go to fanpage!"><img src="img/twitter-bird.png" id="twitBird" alt="twitter bird" /></a>
<a class="fanPageLink" href="http://twitter.com" title="Go to fanpage!">Fanpage</a>

</div>

<div class="content">
<div class="fans"><img src="img/loader.gif" alt="loading.." /></div>
</div>

<div class="subscribe">
<a href="#" class="joinFP">Join!</a>

<div class="membersCount">
<a class="fanPageLink" id="counter" href="http://twitter.com" title="Total Fans"></a>
</div>

</div>
</div>


Here we have the main fanPage container DIV, which holds our the widget and inside it we have the title, content and subscribe DIVs.
These are later styled with CSS and populated with data via AJAX. Also notice that we have three links which share a FanPageLink class. Currently they point to the twitter’s main site, but later we are going to edit their href attributes dynamically, and point them to the member page of the list.
A jQuery Twitter List Powered Fanpage Widget
A jQuery Twitter List Powered Fanpage Widget

Step 2 – CSS

Once we have the markup in place, we can move to the CSS. Here are only presented the rules that are directly used by the widget. You can view all of the code in demo.css in the source archive.

demo.css

#fanPage{
    /* This is the container that holds the widget */
    background-color:#002233;
    color:white;
    height:300px;
    margin:30px auto;
    padding:10px;
    text-align:left;
    width:170px;
}

#fanPage a, #fanPage a:visited{
    /* This styles the title and total fans links */
    color:white;
   text-decoration:none;
}

#fanPage a:hover{
    text-decoration:underline;
}

.title{
   /* The title on the top */
    background-color:#013853;
   font-family:&amp;quot;Myriad Pro&amp;quot;,Arial,Helvetica,sans-serif;
    font-size:16px;
    letter-spacing:1px;
    margin:3px 0 10px;
    padding:4px 8px;
   position:relative;
    text-align:right;
   text-transform:uppercase;
}

#twitBird{
    /* The twitter icon on the top */
    left:-10px;
    position:absolute;
    top:-28px;
}

.content{
    /* The div that holds the twitter avatars */
    background-color:#eeeeee;
    padding:6px;
    text-align:left;
    height:208px;
    position:relative;
    color:#333333;
}

#mask{
    /* Inserted once you click the green &amp;quot;Join&amp;quot; button */
    font-size:10px;
    left:0;
    padding:10px;
    position:absolute;
    top:0;
}

#mask label{
    display:block;
    font-weight:bold;
    margin:8px 0 4px;
   text-transform:uppercase;
}

#twitterName{
    /* The twitter name input box */
    background-color:#FCFCFC;
    border:1px solid #CCCCCC;
    color:#333333;
    font-family:Arial,Helvetica,sans-serif;
    font-size:12px;
    padding:2px;
}

#mask a.greyButton,#mask a.greyButton:visited{
    /* The default state of the gray join button */
    display:inline-block;
    height:19px;
   margin-top:10px;
    padding:6px 0 0;
    text-align:center;
    width:70px;
    background:url(img/button_gray.png) no-repeat;
    color:#222222;
}

#mask a.greyButton:hover{
    /* The hover effect on the &amp;quot;Join&amp;quot; button */
    background-position:bottom left;
    text-decoration:none;
}

div#mask a, div#mask a:hover, div#mask a:visited{
    color:#0196e3;
}

#response{
    /* The div that holds the response messages in the &amp;quot;Join area&amp;quot; */
    margin-top:10px;
    font-size:10px;
   text-align:center;
}

.subscribe{
    position:relative;
}

.membersCount{
    /* The total number of fans div */
   position:absolute;
    right:0;
    top:5px;
    color:white;
    display:block;
    font-size:22px;
    font-weight:bold;
}

content img{
    /* The twitter avatars */
    margin:2px;
}

#fanPage, .content, .title{
   /* Rounding three elements at once */
    -moz-border-radius:4px;
    -webkit-border-radius:4px;
   border-radius:4px;
}

.a.joinFP, a.joinFP:hover{
    /* The green &amp;quot;Join&amp;quot; button */
    display:block;
   background:url(img/buttons.png) no-repeat;
    width:94px;
    height:38px;
    text-indent:-9999px;
   margin:5px 0 0 -4px;
}

.a.joinFP:hover{
    /* The hover state of the button */
    background-position:bottom left;
}

a img{
    border:none;
}

Step 3 – jQuery

As I mentioned earlier, the entire widget is AJAX based. This is actually a necessity, because communication with the twitter API would stall the website otherwise.
Here is the main idea behind the code below:
  1. The page, in which the widget is included is loaded into a visitor’s browser;
  2. With it, script.js (which holds all of our jQuery code) is executed;
  3. $(document).ready() is run;
  4. An AJAX request is initiated, which loads the data from load.php and displays it on success;
  5. All the links with a fanPageLink class are pointed to the list members page on twitter;
  6. A click function is bonded to the green join button;

First half of script.js

$(document).ready(function(){
   /* Executed on DOM load */

    $.getJSON(&quot;load.php&quot;,function(data){

        /* Loading the widget data */
        if(data.error)
       {
            /* If there is an error, output and exit */
            $(&quot;.content&quot;).html(data.error);
           return false;
       }

        $(&quot;.content .fans&quot;).html(&#039;&#039;);
        /* Remove the rotating GIF */

       $.each(data.members,function(i,val){

           /* Loop through all the shown members and add them to the .content DIV */
            $(&quot;.content .fans&quot;).append(&#039;&lt;a href=&quot;http://twitter.com/&#039;+i+&#039;&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;&#039;+val+&#039;&quot; width=&quot;48&quot; height=&quot;48&quot; title=&quot;&#039;+i+&#039;&quot; alt=&quot;&#039;+i+&#039;&quot; /&gt;&lt;/a&gt;&#039;);
        });

        $(&#039;#counter&#039;).html(data.membersCount);
        /* Set the member counter */

        $(&#039;.fanPageLink&#039;).attr(&#039;href&#039;,data.fanPage+&#039;/members&#039;).attr(&#039;target&#039;,&#039;_blank&#039;);
        /* Set the .fanPageLink-s to point to the profile page */
   });

   $(&#039;.joinFP&#039;).click(function(e){

        /* IF the green button has been clicked.. */

       if($(&#039;.content&#039;).html().indexOf(&#039;id=&quot;mask&quot;&#039;)!=-1)
      {
           /* ..and the form is already shown exit */
            e.preventDefault();
           return false;
       }

       /* ..in the other case, start a fade out effect */
        $(&quot;.content .fans&quot;).fadeOut(&quot;slow&quot;,function(){

            $(&#039;.content&#039;).append(&#039;&lt;div id=&quot;mask&quot;&gt;\
            To join our fan page, you just have to fill in your name\
            &lt;label&gt;Twitter username:&lt;/label&gt;\
            &lt;input id=&quot;twitterName&quot; name=&quot;twitter&quot; type=&quot;text&quot; size=&quot;20&quot; /&gt;\
            &lt;a href=&quot;&quot; class=&quot;greyButton&quot; onclick=&quot;sendData();return false;&quot;&gt;Join!&lt;/a&gt; or &lt;a href=&quot;#&quot; onclick=&quot;cancel();return false;&quot;&gt;cancel&lt;/a&gt;\
            &lt;div id=&quot;response&quot;&gt;&lt;/div&gt;\
            &lt;/div&gt;&#039;);
        });

        /* Prevent the link from redirecting the page */
        e.preventDefault();
    });
});

Later if a click occurs on the green  “Join” button, the avatars are faded out and a form appears on their place.
The second half of the code handles the sending of the data to add.php:

Second half of script.js

function sendData()
{
    /* This function sends the form via AJAX */
    $('#response').html('<img src="img/loader.gif" />');
    var twitter = $('#twitterName').val();
    if(!twitter.length)
    {
        $('#response').html('<span style="color:red">Please fill in your twitter username.</span>');
        return false;
    }

    $.ajax({
        type: "POST",
        url: "add.php",
        data: "twitter="+encodeURIComponent(twitter),
        /* Sending the filled in twitter name */
        success: function(msg){

           /* PHP returns 1 on success, and 0 on error */
            var status = parseInt(msg);

            if(status)
            {
                $('#response').html('Thank you for being a fan! You will be added in a few minutes. <a href="#" onclick="cancel();return false">Hide this form</a>.');
                $('#twitterName').val('');
           }
            else
                $('#response').html('<span style="color:red">There is no such twitter user.</span>');
        }
    });
}

function cancel()
{
    /* Hides the "Join" form */
    $('#mask').remove();
    $('.content .fans').fadeIn('slow');
}


The sendData function is called if the user clicks on the newly created gray “Join” button below the input field. It also checks the return status of the AJAX request to choose the proper status message.
Also remember that for above code the work, we need to include the jQuery library and script.js into the head section of the document:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="script.js"></script>

Step 4 – PHP

Now that we followed all the code on the front-end, it is now time for the last part of this tutorial – the PHP back-end.
PHP has the important task of communicating with the twitter API. This is done via a special extension – CURL. For convenience, I made a special function – curlMe that wraps the CURL code and makes it easier to send requests from other places in the script.

functions.php

function error($msg)
{
    // Format the error as a JSON object and exit the script:
    die('{error:"'.$msg.'"}');
}

function fetchElement($element,$src)
{
    // Takes in an XML document as string $src, and returns the required nod value

    $match = array();
    preg_match_all('/<'.$element.'>(.*)<\/'.$element.'>/u',$src,$match);
    // Matching the required property in the xml

    return $match[1];

    // ..and returning it
}

function curlMe($url,$gp='')
{
    // Using CURL to communicate with the Twitter API

    global $username,$password;

    $cc = curl_init();

    curl_setopt($cc, CURLOPT_URL, $url);

    if($gp)
    {
        // If the $gp parameter is set, send it by a POST request:
        curl_setopt($cc, CURLOPT_POST, 1);
        curl_setopt($cc, CURLOPT_POSTFIELDS, $gp);
    }
    else
        curl_setopt($cc, CURLOPT_GET, 1);

    curl_setopt($cc, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    curl_setopt($cc, CURLOPT_USERPWD, $username.':'.$password);
    curl_setopt($cc, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($cc, CURLOPT_RETURNTRANSFER, 1);

    $xml = curl_exec($cc);
    curl_close($cc);

    return $xml;
}

Now that we’ve defined those functions, we can use them in any PHP file by just including or requiring functions.php in the script.
Adding new fans on the list is done in add.php

add.php

require "functions.php";
require "config.php";

if(!$_POST['twitter'])
die('0');

$userXML = curlMe("http://twitter.com/users/show.xml?screen_name=".urlencode($_POST['twitter']));
// Initiating an API request

if(strpos($userXML,'<error>Not found</error>') !== false)
{
    // If there is no such user, return an error:
    die('0');
}

// fetchElement returns an array, and the list function assigns its first element to $id:
list($id) = fetchElement('id',$userXML);

curlMe('http://api.twitter.com/1/'.$username.'/'.$list.'/members.xml','id='.$id);

echo 1;

As with any API, there are limits of usage. This is done to prevent abuse of the service and ruining everybody’s day. Twitter enforces a 150 requests per hour rule, which limits how many times we can GET data for the twitter list.
This is why I build a simple caching mechanism, that stores the fetched data for 15 minutes after a request is made to the API.
Here is how it works:
  1. The widget makes an AJAX request to load.php;
  2. The php script checks to see if a cache file exists;
  3. If it does, it gets its contents and returns it;
  4. If it does not, or if the cache is older than 15 minutes, it fetches the data from the API, stores it in the cache file for later use and returns it;
This simple mechanism ensures that the widget will always have API calls to spare. You can see the code below:

load.php'

require "functions.php";
require "config.php";

$cache_file = 'twitter.cache';
// The cache file

$cache_expire_time = 15*60;
// The cache expires after 15 minutes

$twitterers_shown = 12;

// If you are making changes and want to destroy the cache while testing,
// uncomment the line below:

//$cache_expire_time = 1;

if(!file_exists($cache_file) || time() - filemtime($cache_file) > $cache_expire_time)
{
    // If there isn't a cache file, or if it is older than allowed

    $xml = curlMe("http://api.twitter.com/1/".$username."/".$list."/members.xml");
    //$xml = curlMe("http://api.twitter.com/1/chouka/design/members.xml");

    if(strpos($xml,'<error>Not found</error>') !== false)
    {
        // If there is not such a list, create it automatically:
        curlMe('http://api.twitter.com/1/'.$username.'/lists.xml','name='.$list);
    }

    $usernames = fetchElement('screen_name',$xml);
    $avatars = fetchElement('profile_image_url',$xml);

    $json = '';
    foreach($usernames as $k=>$u)
    {
        if($k!=0) $json.=', ';
       $json.='"'.$u.'":"'.$avatars[$k].'"';
        // Generating the json object with a structure: username:avatar_image

        if($k>=$twitterers_shown-1) break;
    }

    // Getting the total number of fans requires an additional API call:

    $membersXML = curlMe("http://api.twitter.com/1/".$username."/lists/".$list.".xml");
    $membersCount = fetchElement('member_count',$membersXML);

    $json = '{members:{'.$json.'}, membersCount:'.$membersCount[0].',fanPage:"http://twitter.com/'.$username.'/'.$list.'"}';

    // Save the generated json variable in the cache for later use:
    $fp = fopen($cache_file,'w');

    if($fp == false)
    {
        error("Your cache file could not be created! You have to chmod the script directory to 777!");
    }

    fwrite($fp,$json);
    fclose($fp);
}
else
{
    $json = file_get_contents($cache_file);
    // Fetch the data from the cache file
}

echo $json;

Also you might notice that the API requires you to provide you username and password in order to use it. So if you are planning to run the demo on your own server, be sure to fill in your log-in information in config.php.
The two states
With this our Twitter List Powered Fan Page is complete!














 

 


No comments:

Post a Comment

Next Next home

RECENT COMMENTS

Grab This Widget

Random posts

 

Powered by FeedBurner

Subscribe to updates
Blog-Watch - The Blog Directory
Computers blogs
googlef97e20b47bd40d74.html
The Link Exchange - Your ultimate resource for link exchange!
Technology Blogs - Blog Rankings
Computers Blogs
GoLedy.com
Blog Directory
Technology Blogs - Blog Rankings
Blog Directory
Blog Directory
Listed in LS Blogs the Blog Directory and Blog Search Engine

I'm in

I'm in
Reddit [Mithun Mohan]

Follow me in twitter

Follow me in twitter
[Brilliant Computing]

See me in Delicious

See me in Delicious
Mithun Mohan

Find me in stumble upon

Find me in stumble upon
[Mithun Mohan]

Lets become friends in digg

Lets become friends in digg
[Brilliant Computing]

The Brilliant Computing community in Orkut

VISITORS

   
MyFreeCopyright.com Registered & Protected

TERMS AND CONDITIONS

Dear Visitors...
This blog does not contain uploaded files on the server but only provides direct links to download files.Navigate the links provided at your own risk.If any problem occurs like broken link or something or virus then you can contact me via 'Contact Me' found on top of this blog so that I can change the link.Dont hesitate to comment.If Any request or suggestions plz contact me.
DO THE HACKS POSTED HERE AT YOUR OWN RISK.
Thankyou for visiting my blog............enjoy

Protected by Copyscape Plagiarism Detector
function rtclickcheck(keyp){ if (navigator.appName == "Netscape" && keyp.which == 3){ alert(message); return false; } if (navigator.appVersion.indexOf("MSIE") != -1 && event.button == 2) { alert(message); return false; } } document.onmousedown = rtclickcheck;

Brilliant Computing Copyright © 2009 Brilliant Computing is Designed by Ipietoon Sponsored by Online Business Journal

Creative Commons License
Brilliant computing by Mithun is licensed under a Creative Commons Attribution-Noncommercial 2.5 India License.