Subscribe

Sunday 7 March 2010

Using Flickr Feed To Create Blogger Gadget

Hi there folks I am back with something different this time around. As this blog deals with widgets and gadgets, one side of the story which I missed out was Blogger gadgets, as you all know who have worked on blogger sometime or the other, these gadgets as they call make your blog either more intresting or adds value to your site. Thus this topic got me intrested. In one of my previous blog, I dealt with getting javascript working on wordpress, the same can be done to some extent with blogger.Unfortunately I dont beleive it to be the best way out.
Gadgets are the proper way of organising your site interface and avoiding unecessary clutter.
Blogger gadgets are nearly same as the google gadgets which you use on your igoogle page.
First thing to understand is these gadgets are nothing more than XML files with HTML/javascript thrown into the mixture. Therefore if you are an experienced HTML developer or Javascript developer, you will fit right into it.
As usual lets talk about some basic theory, google as well as blogger gadgets have this structure you must follow
Basic Theory
<?xml version="1.0" encoding="UTF-8" ?>    
<Module>     
  <ModulePrefs title="hello world example" /> 

<UserPref……/>    
  <Content type="html">     
     <![CDATA[     
       Hello, world!     
     ]]>     
  </Content>     
</Module>

Lets try to figure out each element one by one
Module tag as we know is the root element of the XML file. Everything else is contained inside this element
ModulePrefs tag creates the meta-data for your gadget to be used by any site which is hosting this gadget either it is blogger or orkut or igoogle. These are the few customizations which google API provides for you
Following few lines are exact copy from http://code.google.com/apis/gadgets/docs/reference.html
Attribute Description
title
Optional string that provides the title of the gadget. This title is displayed in the gadget title bar on iGoogle. If this string contains
user preference substitution variables and you are planning to submit your gadget to the iGoogle content directory, you should also provide a directory_title for directory display.
title_url
Optional string that provides a URL that the gadget title links to. For example, you could link the title to a webpage related to the gadget.

description
Optional string that describes the gadget.

author
Optional string that lists the author of the gadget.

author_email
Optional string that provides the gadget author's email address. You can use any email system, but you should not use a personal email address because of spam. One approach is to use an email address of the form helensmith.feedback+coolgadget@gmail.com in your gadget spec.
Gmail drops everything after the plus sign (+), so this email address is interpreted as helensmith.feedback@gmail.com.
You can create a Gmail account
here.
screenshot
Optional string that gives the URL of a gadget screenshot. This must be an image on a public web site that is not blocked by robots.txt. PNG is the preferred format, though GIF and JPG are also acceptable. Gadget screenshots should be 280 pixels wide. The height of the screenshot should be the "natural" height of the gadget when it's in use.

thumbnail
Optional string that gives the URL of a gadget thumbnail. This must be an image on a public web site that is not blocked by robots.txt. PNG is the preferred format, though GIF and JPG are also acceptable. Gadget thumbnails should be 120x60 pixels.


Then comes UserPref tag, this tag is the customization element for your gadget, for example you may require some data for the gadget to work like username or password, this is the element which provides the user with the opportunity to enter data for the gadget. Have a look at the picture below, this is like form which is presented to you when you either install the gadget for the first time or when you edit it later on
blog1
As mentioned all the userpref’s are provided by the author of the gadget, in my case it was pretty simple I provided the Tag to search and Refresh Rate, rest of the customization is provided by the gadget itself you don’t have to worry about it.
UserPref can have the following attributes
name
Required "symbolic" name of the user preference; displayed to the user during editing if no display_name is defined. Must contain only letters, number and underscores, i.e. the regular expression ^[a-zA-Z0-9_]+$. Must be unique.
display_name
Optional string to display alongside the user preferences in the edit window. Must be unique.
urlparam
Optional string to pass as the parameter name for content type="url".
datatype
Optional string that indicates the data type of this attribute. Can be string, bool, enum, hidden (a string that is not visible or user editable), or list(dynamic array generated from user input). The default is string.
required
Optional boolean argument (true or false) indicating whether this user preference is required. The default is false.
default_value
Optional string that indicates a user preference's default value.
Moving forward the next element of interest is Content. It is the heart and soul of your gadget or in simple terms the basic body of this gadget is the content section.Content section may have URL type or HTML type. In this post we will discuss HTML type. Inside this tag you place your HTML or javascript. these must be contained in a CDATA section. You can link to external JS files too.
This is the basic hierarchy of a google/blogger gadget. Now we are ready to define the gadget we need to build.

Gadget Creation

In this post I shall create a slide show gadget of random pictures from Flickr based on any tag that you provide. This gadget may be used from anywhere and can be downloaded from here.
Firstly we must understand that Flickr provides us with an API to interact with itself, therefore we must make a request just like an XMLHTTPRequest shown in my previous post. Unfortunately this is not possible. Why because cross-domain XMLHTTPRequest is not allowed.The reason for this is a topic in itself and we shall not go into it here. Suffice to say that it creates more headaches rather than solutions. But don not despair help is on hand in the form of jquery. JQuery provides us with a handy function to make cross domain request thus we do not need to get stuck with some ugly server code.
$.getJSON is the function which we will call to get the feed in JSON format from Flickr. If you want to know more about jquery please send me a mail and I  will do a tutorial for that. At present my jquery function gets the photos and adds two divs for each photo, one has the pic and the other has the tile. All the divs except the first one are hidden and we will use jquery to show and hide them.
The user can give us the tag to search and the refresh rate that is the time between changing of two images.
function getimages(tags)    
{ 

    var query="http://api.flickr.com/services/feeds/photos_public.gne?tags=" + tags + "&tagmode=any&format=json&jsoncallback=?";     
var x=$.getJSON(query,function(data){     
    var htmlstr="";     
    var htmltxt="";     
    var div_img=$('#PlaceImages');     
    var div_txt=$('#PlaceText');     
    $.each(data.items,function(i,item)     
    {     
        var sourceSquare = (item.media.m).replace("_m.jpg", "_s.jpg");     
        htmlstr="<a target='_blank' href='" + item.link + "'><img src='" + item.media.m + "' width='100%' height='90%'/></a>";     
        htmltxt="<a target='_blank' href='" + item.link + "' >" + item.title + " </a>";     
        if(i>0)     
        {     
            div_img.append("<div id='div" + i.toString() + "' style='left:0px;top:0px;display:none;width:100%;height:99%;z-index:"+i+"'>" + htmlstr +"</div>");     
            div_txt.append("<div id='div_txt" + i.toString() + "' style='left:0px;top:0px;display:none;width:100%;height:99%;z-index:"+i+"'>" + htmltxt +"</div>");     
        }     
        else     
        {     
            div_img.append("<div id='div" + i.toString() + "' style='left:0px;top:0px;height:100%;width:99%"+i+"'>" + htmlstr +"</div>");     
            div_txt.append("<div id='div_txt" + i.toString() + "' style='left:0px;top:0px;width:100%;height:99%;z-index:"+i+"'>" + htmltxt +"</div>");     
        } 

    }    
    );

    });    
}

Looks complicated but it is not, everything is being done by jquery. In our original document we have two divs one is called PlaceImages and the other is called PlaceText. What I am doing is appending a new div for each image object. Therefore htmlstr creates a link with the image object and the script puts this link in the new div, each new div has a unique name which is created by “div” + the sequence number. This will be used later. Same is true for the PlaceText div where a new div with the photo title is added.
Most important part of all this is the divs so created are all hidden except the first one div0 and div_txt0. How do we unhide them that will be shown later. I hope I have made my point clear. After the this function finishes the control is returned to the original function shown below.
function getPics() {    
    var prefs = new _IG_Prefs();     
    var tags = prefs.getString("tags");     
    rate=parseInt(prefs.getString("rate"));     
    var linkColor=document.getElementById("PlaceText");     
    linkColor.style.color=gadgets.skins.getProperty('CONTENT_LINK_COLOR');     
    document.body.style.borderColor = gadgets.skins.getProperty('CONTENT_BG_COLOR');     
    getimages(tags);     
    id=setInterval("changeImage()",32000);     
}

This is the function which is executed when the gadget is loaded. Thus the first line creates a new preference object which will get us all the user preference values.Next two lines get the tag and refresh rate from the user preference. Again I have tried to show you how the blogger widget can use the gadgets.skin class to get the different values for the theme being used and modify your gadget CSS accordingly. Finally we call our function getimages with the user given tag. After the function has been called a timer is set up which will fire every 32000 milli second.Each time the timer is fired the function changeImage will be called.
As mentioned above all the showing and hiding is done in this function, basically this function handles the slide show and disables or enables the timer.
function changeImage()    
    {     
        var y=$('#PlaceImages>div:visible').attr('id');     
        var txt=$('#PlaceText>div:visible').attr('id');     
        //alert(y);     
        if(y!=undefined)     
        {     
            clearInterval(id);     
            var temp1=y.charAt(y.length-1);     
            var temp2=y.charAt(y.length-2);     
            var num=0;     
            if(isNaN(temp2)!=true)     
            {     
                num=parseInt(temp2)*10 + parseInt(temp1);     
            }     
            else     
                num=parseInt(temp1);     
            num+=1;     
            if(num>=20)     
                num=0;     
            hidediv="#" + y;     
            showdiv="#div" + num.toString();     
            showdiv_txt="#div_txt" + num.toString();     
            hidediv_txt="#"+txt;     
            $(showdiv).fadeIn('slow');     
            $(showdiv_txt).fadeIn('fast');     
            $(hidediv).fadeOut('slow');     
            $(hidediv_txt).fadeOut('slow');     
            if(isNaN(rate)==true)     
                rate=9500;     
            id=setInterval("changeImage()",rate);     
        }     
    }

I shall not go into the details of the code because it is quite clear what is going on.  Each time it selects the visible div and using the number at the end of the id shows the next div while the original is hidden. If div0 was visible to start with next time this function gets called div1 is visible and div0 is hidden. Thus creating a slide show. The whole code is shown below .If you want to see this widget working please visit http://widgetsgadgetsworld.blogspot.com/
<?xml version="1.0" encoding="UTF-8"?>   
<Module>    
    <ModulePrefs    
    title="Flickr Photo"    
    author="Someone"    
    title_url="http://best-news-site.com/"    
    author_email="somewhere@lycos.com"    
    description="Flickr image slide show">    
        <Require feature="opensocial-0.7"/>    
        <Require feature="google.blog"/>    
        <Require feature="skins"/>    
        <Require feature="views"/>    
    </ModulePrefs>    
    <UserPref display_name="Tag To Search" name="tags" datatype="string" default_value="india"    
              ></UserPref>    
    <UserPref display_name="Refresh Rate(ms)" name="rate" datatype="string" default_value="9500"    
              ></UserPref>    
    <Content type="html">    
        <![CDATA[    
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>    
<div id="PlaceImages"  style="width:100%;height:90%; overflow:hidden;float:left;"></div><br />    
<div id="PlaceText" style="width:100%;height:8%; text-align:center;overflow:hidden; clear:both;"></div>    
<script type="text/javascript">    
var rate=9500;    
var id;    
function getimages(tags)    
{ 

    var query="http://api.flickr.com/services/feeds/photos_public.gne?tags=" + tags + "&tagmode=any&format=json&jsoncallback=?";    
var x=$.getJSON(query,function(data){    
    var htmlstr="";    
    var htmltxt="";    
    var div_img=$('#PlaceImages');    
    var div_txt=$('#PlaceText');    
    $.each(data.items,function(i,item)    
    {    
        var sourceSquare = (item.media.m).replace("_m.jpg", "_s.jpg");    
        htmlstr="<a target='_blank' href='" + item.link + "'><img src='" + item.media.m + "' width='100%' height='90%'/></a>";    
        htmltxt="<a target='_blank' href='" + item.link + "' >" + item.title + " </a>";    
        if(i>0)    
        {    
            div_img.append("<div id='div" + i.toString() + "' style='left:0px;top:0px;display:none;width:100%;height:99%;z-index:"+i+"'>" + htmlstr +"</div>");    
            div_txt.append("<div id='div_txt" + i.toString() + "' style='left:0px;top:0px;display:none;width:100%;height:99%;z-index:"+i+"'>" + htmltxt +"</div>");    
        }    
        else    
        {    
            div_img.append("<div id='div" + i.toString() + "' style='left:0px;top:0px;height:100%;width:99%"+i+"'>" + htmlstr +"</div>");    
            div_txt.append("<div id='div_txt" + i.toString() + "' style='left:0px;top:0px;width:100%;height:99%;z-index:"+i+"'>" + htmltxt +"</div>");    
        } 

    }   
    );

    });   
}    
 function getPics() {    
    var prefs = new _IG_Prefs();    
    var tags = prefs.getString("tags");    
    rate=parseInt(prefs.getString("rate"));    
    var linkColor=document.getElementById("PlaceText");    
    linkColor.style.color=gadgets.skins.getProperty('CONTENT_LINK_COLOR');    
    document.body.style.borderColor = gadgets.skins.getProperty('CONTENT_BG_COLOR');    
    getimages(tags);    
    id=setInterval("changeImage()",32000);    
} 

function changeImage()   
    {    
        var y=$('#PlaceImages>div:visible').attr('id');    
        var txt=$('#PlaceText>div:visible').attr('id');    
        //alert(y);    
        if(y!=undefined)    
        {    
            clearInterval(id);    
            var temp1=y.charAt(y.length-1);    
            var temp2=y.charAt(y.length-2);    
            var num=0;    
            if(isNaN(temp2)!=true)    
            {    
                num=parseInt(temp2)*10 + parseInt(temp1);    
            }    
            else    
                num=parseInt(temp1);    
            num+=1;    
            if(num>=20)    
                num=0;    
            hidediv="#" + y;    
            showdiv="#div" + num.toString();    
            showdiv_txt="#div_txt" + num.toString();    
            hidediv_txt="#"+txt;    
            $(showdiv).fadeIn('slow');     
            $(showdiv_txt).fadeIn('fast');    
            $(hidediv).fadeOut('slow');    
            $(hidediv_txt).fadeOut('slow');    
            if(isNaN(rate)==true)    
                rate=9500;    
            id=setInterval("changeImage()",rate);    
        }    
    }    
 gadgets.util.registerOnLoadHandler(getPics); 

</script> 

]]> 

    </Content>   
</Module>

1 comment:

 
EatonWeb Blog Directory