<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tutorialzine &#187; Search Results  &#187;  YQL</title>
	<atom:link href="http://tutorialzine.com/search/YQL/feed/rss2/" rel="self" type="application/rss+xml" />
	<link>http://tutorialzine.com</link>
	<description>Web Development Tutorials &#38; Resources</description>
	<lastBuildDate>Mon, 14 May 2012 09:13:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>How to use Geolocation and Yahoo&#8217;s APIs to build a simple weather webapp</title>
		<link>http://tutorialzine.com/2012/05/weather-forecast-geolocation-jquery/</link>
		<comments>http://tutorialzine.com/2012/05/weather-forecast-geolocation-jquery/#comments</comments>
		<pubDate>Mon, 14 May 2012 09:13:18 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1985</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2012/05/weather-forecast-geolocation-jquery/"><img src="http://cdn.tutorialzine.com/img/featured/1985.jpg" /></a></div> Today we will be using the HTML5 Geolocation API to present the user with a personalized weather forecast.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2012/05/weather-forecast-geolocation-jquery/"><img src="http://cdn.tutorialzine.com/img/featured/1985.jpg" /></a></div> <p>Today we will be using the HTML5 geolocation API to present the user with a personalized weather forecast. Using jQuery, we will issue AJAX request to two of Yahoo&#8217;s popular APIs to obtain additional geographical information and a weather forecast. This example also makes use of the wonderful <a href="http://adamwhitcroft.com/climacons/" target="_blank">climacons icon set</a>.</p>
<h3>Obtaining an Application Key</h3>
<p>Yahoo provides a <a href="http://developer.yahoo.com/everything.html" target="_blank">large collection of useful APIs</a> that are free for developers to use. The requirement is that you register your application with through their <a href="https://developer.apps.yahoo.com/dashboard/createKey.html" target="_blank">developer dashboard</a>. The registration is simple and straightforward, and as a result you obtain an application id (look for it under the title of your application). You are going to need this later in the tutorial, but first let&#8217;s see how everything would work together.</p>
<h3>The Idea</h3>
<p>Here is what we need to do in order to display our weather forecast:</p>
<ul>
<li>First we&#8217;ll use the <em>Geolocation API</em> supported by modern browsers. The API will prompt the user to authorize location access and will return a set of GPS coordinates;</li>
<li>Next, we will issue a request to Yahoo&#8217;s <a href="http://developer.yahoo.com/geo/placefinder/" target="_blank">PlaceFinder API</a>, passing the above coordinates. This will give us the name of the city and country, and a <strong>woeid</strong> &#8211; a special ID used to identify the city in weather forecasts;</li>
<li>Finally, we will issue a request to Yahoo&#8217;s <a href="http://developer.yahoo.com/weather/" target="_blank">Weather API</a> with that woeid. This will give us current weather conditions, as well as a forecast for the rest of the current and the next day.</li>
</ul>
<p>Great! We are now ready for the HTML.</p>
<div id="attachment_1996" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2012/05/weather-forecast-geolocation-jquery/"><img class="size-full wp-image-1996" title="Weather Forecast Web App" src="http://cdn.tutorialzine.com/wp-content/uploads/2012/05/jquery-geolocation-weather-app.jpg" alt="Weather Forecast Web App" width="620" height="460" /></a><p class="wp-caption-text">Weather Forecast Web App</p></div>
<h3>The HTML</h3>
<p>We will start with a blank HTML5 document, and we will add a reference to our stylesheet to the head section, along with two fonts from <a href="http://www.google.com/webfonts" target="_blank">Google&#8217;s Webfonts</a> library. In the body we will add a h1 header and markup for the weather forecast slider.</p>
<h4>index.html</h4>
<pre class="brush:html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset="utf-8" /&gt;
        &lt;title&gt;Weather Forecast with jQuery &amp;amp; Yahoo APIs | Tutorialzine Demo&lt;/title&gt;

        &lt;!-- The stylesheet --&gt;
        &lt;link rel="stylesheet" href="assets/css/styles.css" /&gt;

        &lt;!-- Google Fonts --&gt;
        &lt;link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Playball|Open+Sans+Condensed:300,700" /&gt;

        &lt;!--[if lt IE 9]&gt;
          &lt;script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"&gt;&lt;/script&gt;
        &lt;![endif]--&gt;
    &lt;/head&gt;

    &lt;body&gt;

		&lt;header&gt;
			&lt;h1&gt;Weather Forecast&lt;/h1&gt;
		&lt;/header&gt;

        &lt;div id="weather"&gt;

        	&lt;ul id="scroller"&gt;
        		&lt;!-- The forecast items will go here --&gt;
        	&lt;/ul&gt;

        	&lt;a href="#" class="arrow previous"&gt;Previous&lt;/a&gt;
        	&lt;a href="#" class="arrow next"&gt;Next&lt;/a&gt;

        &lt;/div&gt;

        &lt;p class="location"&gt;&lt;/p&gt;

        &lt;div id="clouds"&gt;&lt;/div&gt;

        &lt;!-- JavaScript includes - jQuery, turn.js and our own script.js --&gt;
		&lt;script src="http://code.jquery.com/jquery-1.7.2.min.js"&gt;&lt;/script&gt;
		&lt;script src="assets/js/script.js"&gt;&lt;/script&gt;

    &lt;/body&gt;
&lt;/html&gt;</pre>
<p>Before the closing body tag we are adding the latest version of jQuery and our script.js file, which we are discussing in the following sections.</p>
<h3>The JavaScript</h3>
<p>The first step is to define two configuration variables in <strong>/assets/js/script.js</strong>:</p>
<pre class="brush:js">var APPID = '';	// Your Yahoo Application ID
var DEG = 'c';	// c for celsius, f for fahrenheit</pre>
<p>These are passed as parameters with the AJAX requests for the location and weather APIs as you will see in a moment.</p>
<p>Following the outline in the idea section, we should now look into using the <em>HTML5 Geolocation API</em> to obtain a set of GPS coordinates. This API is supported by all new browsers including IE9 and mobile devices. To use it, we need to test whether the global navigator object has a <strong>geolocation</strong> property. If it does, we call its <strong>getCurrentPosition</strong> method passing two event handling functions for success and failure. Here is the relevant code from <strong>script.js</strong> that does this:</p>
<pre class="brush:js">// Does this browser support geolocation?
if (navigator.geolocation) {
	navigator.geolocation.getCurrentPosition(locationSuccess, locationError);
}
else{
	showError("Your browser does not support Geolocation!");
}

function locationSuccess(position) {
	var lat = position.coords.latitude;
	var lon = position.coords.longitude;

	// We will make further requests to Yahoo's APIs here
}

function locationError(error){
	switch(error.code) {
		case error.TIMEOUT:
			showError("A timeout occured! Please try again!");
			break;
		case error.POSITION_UNAVAILABLE:
			showError('We can\'t detect your location. Sorry!');
			break;
		case error.PERMISSION_DENIED:
			showError('Please allow geolocation access for this to work.');
			break;
		case error.UNKNOWN_ERROR:
			showError('An unknown error occured!');
			break;
	}

}

function showError(msg){
	weatherDiv.addClass('error').html(msg);
}</pre>
<p>The <strong>locationSuccess</strong> function is where we will be issuing requests to Yahoo&#8217;s APIs in a moment. The <strong>locationError</strong> function is passed an error object with the specific reason for the error condition. We will use a <strong>showError</strong> helper function to display the error messages on the screen.</p>
<p>The full version of <em>locationSuccess</em> follows:</p>
<pre class="brush:js">function locationSuccess(position) {
	var lat = position.coords.latitude;
	var lon = position.coords.longitude;

	// Yahoo's PlaceFinder API http://developer.yahoo.com/geo/placefinder/
	// We are passing the R gflag for reverse geocoding (coordinates to place name)
	var geoAPI = 'http://where.yahooapis.com/geocode?location='+lat+','+lon+'&amp;flags=J&amp;gflags=R&amp;appid='+APPID;

	// Forming the query for Yahoo's weather forecasting API with YQL
	// http://developer.yahoo.com/weather/

	var wsql = 'select * from weather.forecast where woeid=WID and u="'+DEG+'"',
		weatherYQL = 'http://query.yahooapis.com/v1/public/yql?q='+encodeURIComponent(wsql)+'&amp;format=json&amp;callback=?',
		code, city, results, woeid;

	// Issue a cross-domain AJAX request (CORS) to the GEO service.
	// Not supported in Opera and IE.
	$.getJSON(geoAPI, function(r){

		if(r.ResultSet.Found == 1){

			results = r.ResultSet.Results;
			city = results[0].city;
			code = results[0].statecode || results[0].countrycode;

			// This is the city identifier for the weather API
			woeid = results[0].woeid;

			// Make a weather API request (it is JSONP, so CORS is not an issue):
			$.getJSON(weatherYQL.replace('WID',woeid), function(r){

				if(r.query.count == 1){

					// Create the weather items in the #scroller UL

					var item = r.query.results.channel.item.condition;
					addWeather(item.code, "Now", item.text + ' &lt;b&gt;'+item.temp+'°'+DEG+'&lt;/b&gt;');

					for (var i=0;i&lt;2;i++){
						item = r.query.results.channel.item.forecast[i];
						addWeather(
							item.code,
							item.day +' &lt;b&gt;'+item.date.replace('\d+$','')+'&lt;/b&gt;',
							item.text + ' &lt;b&gt;'+item.low+'°'+DEG+' / '+item.high+'°'+DEG+'&lt;/b&gt;'
						);
					}

					// Add the location to the page
					location.html(city+', &lt;b&gt;'+code+'&lt;/b&gt;');

					weatherDiv.addClass('loaded');

					// Set the slider to the first slide
					showSlide(0);

				}
				else {
					showError("Error retrieving weather data!");
				}
			});

		}

	}).error(function(){
		showError("Your browser does not support CORS requests!");
	});

}</pre>
<p>The PlaceFinder API returns its results as plain JSON. But as it is on a different domain, only browsers that support CORS (cross origin resource sharing) will be able to retrieve it. Most major browsers that support geolocation also support CORS, with the exception of IE9 and Opera, which means that this example won&#8217;t work there.</p>
<p>Another thing to consider is that the weather API returns only two days of forecasts, which somewhat limits the utility of our web app, but unfortunately there is no way around it.</p>
<blockquote class="note"><p>We are only using the Weather API for temperature data, but it provides additional information that you might find useful. You can play with the API and browse the responses in the <a href="http://developer.yahoo.com/yql/console/?q=show%20tables&amp;env=store://datatables.org/alltableswithkeys#h=select%20*%20from%20weather.forecast%20where%20woeid%3D2502265" target="_blank">YQL console</a>.</p></blockquote>
<p>After we retrieve the weather data, we call the <strong>addWeather</strong> function, which creates a new LI item in the <em>#scroller</em> unordered list.</p>
<pre class="brush:js">function addWeather(code, day, condition){

	var markup = '&lt;li&gt;'+
		'&lt;img src="assets/img/icons/'+ weatherIconMap[code] +'.png" /&gt;'+
		' &lt;p class="day"&gt;'+ day +'&lt;/p&gt; &lt;p class="cond"&gt;'+ condition +
		'&lt;/p&gt;&lt;/li&gt;';

	scroller.append(markup);
}</pre>
<p>Now we need to listen for clicks on the previous / next arrows, so we can offset the slider to reveal the correct day of the forecast.</p>
<pre class="brush:js">	/* Handling the previous / next arrows */

	var currentSlide = 0;
	weatherDiv.find('a.previous').click(function(e){
		e.preventDefault();
		showSlide(currentSlide-1);
	});

	weatherDiv.find('a.next').click(function(e){
		e.preventDefault();
		showSlide(currentSlide+1);
	});

	function showSlide(i){
		var items = scroller.find('li');

		// Exit if the requested item does not exist,
		// or the scroller is currently being animated
		if (i &gt;= items.length || i &lt; 0 || scroller.is(':animated')){
			return false;
		}

		// The first/last classes hide the left/right arrow with CSS
		weatherDiv.removeClass('first last');

		if(i == 0){
			weatherDiv.addClass('first');
		}
		else if (i == items.length-1){
			weatherDiv.addClass('last');
		}

		scroller.animate({left:(-i*100)+'%'}, function(){
			currentSlide = i;
		});
	}</pre>
<p><strong>With this our simple weather web app is complete!</strong> You can see everything together in <em>/assets/js/script.js</em>. We won't be discussing the styling here, but you can read through <em>/assets/css/styles.css</em> yourself.</p>
<h3>Done!</h3>
<p>In this example you learned how to use the HTML5 geolocation with Yahoo's Weather and Places APIs to present a location-aware weather forecast. It works on most modern web browsers and mobile devices.</p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2012/05/weather-forecast-geolocation-jquery/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Timeline Portfolio</title>
		<link>http://tutorialzine.com/2012/04/timeline-portfolio/</link>
		<comments>http://tutorialzine.com/2012/04/timeline-portfolio/#comments</comments>
		<pubDate>Mon, 02 Apr 2012 08:16:09 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1920</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2012/04/timeline-portfolio/"><img src="http://cdn.tutorialzine.com/img/featured/1920.jpg" /></a></div> This time we will be using the Timeline jQuery plugin as a dark themed portfolio in which you can showcase projects and important events in your career.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2012/04/timeline-portfolio/"><img src="http://cdn.tutorialzine.com/img/featured/1920.jpg" /></a></div> <p><a href="http://timeline.verite.co/" target="_blank">Timeline</a> is a jQuery plugin specialized in showing a chronological series of events. You can embed all kinds of media including tweets, videos and maps, and associate them with a date. With some design tweaks, this will make it perfect for a portfolio in which you showcase your work and interests.</p>
<h3>The HTML</h3>
<p>Timeline comes with a light colored theme by default. It is perfectly usable and in most cases would be exactly what you need. However, for our portfolio, a dark design would be a better fit, so we will customize it to our liking.</p>
<p>First, let&#8217;s look at the basic layout of the page:</p>
<h4>index.html</h4>
<pre class="brush:html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset="utf-8" /&gt;
        &lt;title&gt;Timeline Portfolio | Tutorialzine Demo&lt;/title&gt;

        &lt;!-- The default timeline stylesheet --&gt;
        &lt;link rel="stylesheet" href="assets/css/timeline.css" /&gt;
        &lt;!-- Our customizations to the theme --&gt;
        &lt;link rel="stylesheet" href="assets/css/styles.css" /&gt;

		&lt;!-- Google Fonts --&gt;
        &lt;link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Dancing+Script|Antic+Slab" /&gt;

        &lt;!--[if lt IE 9]&gt;
          &lt;script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"&gt;&lt;/script&gt;
        &lt;![endif]--&gt;
    &lt;/head&gt;

    &lt;body&gt;

		&lt;div id="timeline"&gt;
			&lt;!-- Timeline will generate additional markup here --&gt;
		&lt;/div&gt;

        &lt;!-- JavaScript includes - jQuery, turn.js and our own script.js --&gt;
		&lt;script src="http://code.jquery.com/jquery-1.7.1.min.js"&gt;&lt;/script&gt;
		&lt;script src="assets/js/timeline-min.js"&gt;&lt;/script&gt;
		&lt;script src="assets/js/script.js"&gt;&lt;/script&gt;

    &lt;/body&gt;
&lt;/html&gt;</pre>
<p>In the head section, we have the plugin&#8217;s stylesheet &#8211; timeline.css, and styles.css, which will hold our customizations. In the footer we have the jQuery library, timeline plugin and <strong>script.js</strong> which initializes it.</p>
<p>When we call the plugin, it will search for a div on your page with the ID of <strong>timeline</strong>. Inside it, it will inserts all the markup it needs to present the timeline:</p>
<pre class="brush:html">&lt;div class="container main" id="timeline"&gt;
	&lt;div class="feature slider" style="overflow-y: hidden;"&gt;
		&lt;div class="slider-container-mask slider-container slider-item-container"&gt;

			&lt;!-- The divs below are the events of the timeline --&gt;

			&lt;div class="slider-item content"&gt;
				&lt;div class="text container"&gt;

					&lt;h2 class="start"&gt;Johnny B Goode&lt;/h2&gt;
					&lt;p&gt;&lt;em&gt;&lt;span class="c1"&gt;Designer&lt;/span&gt; &amp;amp; &lt;span class=
					"c2"&gt;Developer&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;

				&lt;/div&gt;

				&lt;div class="media media-wrapper media-container"&gt;
					&lt;!-- Images or other media go here --&gt;
				&lt;/div&gt;
			&lt;/div&gt;

			&lt;div class="slider-item content content-container"&gt;
				&lt;div class="text container"&gt;

					&lt;h2 class="date"&gt;March 2009&lt;/h2&gt;
					&lt;h3&gt;My first experiment in time-lapse photography&lt;/h3&gt;
					&lt;p&gt;Nature at its finest in this video.&lt;/p&gt;

				&lt;/div&gt;

				&lt;div class="media media-wrapper media-container"&gt;
					&lt;!-- Images or other media go here --&gt;
				&lt;/div&gt;
			&lt;/div&gt;

			&lt;!-- More items go here --&gt;
		&lt;/div&gt;

        &lt;!-- Next arrow --&gt;
		&lt;div class="nav-next nav-container"&gt;
			&lt;div class="icon"&gt;&lt;/div&gt;
			&lt;div class="date"&gt;March 2010&lt;/div&gt;
			&lt;div class="title"&gt;Logo Design for a pet shop&lt;/div&gt;
		&lt;/div&gt;

        &lt;!-- Previous arrow --&gt;
		&lt;div class="nav-previous nav-container"&gt;
			&lt;div class="icon"&gt;&lt;/div&gt;
			&lt;div class="date"&gt;July 2009&lt;/div&gt;
			&lt;div class="title"&gt;Another time-lapse experiment&lt;/div&gt;
		&lt;/div&gt;
	&lt;/div&gt;

	&lt;div class="navigation"&gt;

			&lt;!-- The navigation items go here (the tooltips in the bottom)
                one for each of the events --&gt;

			&lt;div class="time"&gt;
				&lt;!-- The timeline numbers go here --&gt;
			&lt;/div&gt;
		&lt;/div&gt;

		&lt;div class="timenav-background"&gt;
			&lt;div class="timenav-line" style="left: 633px;"&gt;&lt;/div&gt;

			&lt;div class="timenav-interval-background top-highlight"&gt;&lt;/div&gt;
		&lt;/div&gt;

		&lt;div class="toolbar" style="top: 27px;"&gt;
			&lt;div class="back-home icon" title="Return to Title"&gt;&lt;/div&gt;
			&lt;div class="zoom-in icon" title="Expand Timeline"&gt;&lt;/div&gt;
			&lt;div class="zoom-out icon" data-original-title="Contract Timeline"&gt;&lt;/div&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;</pre>
<p>As we will be modifying the CSS of the timeline, the fragment above will give you a better idea of the customizations. Note that we won&#8217;t be recreating the plugin&#8217;s stylesheet from scratch, we will only be overriding some of the rules in our own css file. This has the benefit of making future updates to the plugin straightforward, not to mention that it will be much easier.</p>
<div id="attachment_1931" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2012/04/timeline-portfolio/"><img class="size-full wp-image-1931" title="Timeline Portfolio with jQuery" src="http://cdn.tutorialzine.com/wp-content/uploads/2012/03/timeline-portfolio-jquery.jpg" alt="Timeline Portfolio with jQuery" width="620" height="460" /></a><p class="wp-caption-text">Timeline Portfolio with jQuery</p></div>
<p>Writing the CSS by looking at the markup alone would be a tough undertaking, given that our rules must have <a href="http://css-tricks.com/specifics-on-css-specificity/" target="_blank">precedence</a> over the ones used in <em>timeline.css</em>. Fortunately, there is a much easier way, as you will see in the CSS section of this tutorial.</p>
<h3>The jQuery</h3>
<p>To initialize the plugin, we need to call the VMM.Timeline() method on document ready:</p>
<pre class="brush:js">$(function(){

	var timeline = new VMM.Timeline();
	timeline.init("data.json");

});</pre>
<p>The init method takes single argument &#8211; the data source. It can either be a json file like above, or a Google spreadsheet (reminiscent of our <a title="Dynamic FAQ Section w/ jQuery, YQL &amp; Google Docs" href="http://tutorialzine.com/2010/08/dynamic-faq-jquery-yql-google-docs/">Spredsheet Powered FAQ Tutorial</a>).</p>
<blockquote class="note"><p>For more information on the supported data sources, see the <a href="http://timeline.verite.co/#fileformat" target="_blank">documentation on the plugin&#8217;s site</a>, or browse the data.json file in the zip download for this tutorial.</p></blockquote>
<h3>The CSS</h3>
<p>I used Firebug&#8217;s HTML Inspector to get the right selectors for the elements that we are about to customize. In the HTML tab, it is easy to see what rules have been applied to each element by <em>timeline.css</em>. To override them, I copied the same selectors to <em>styles.css</em> which is where our modifications will take place. On several occurrences, however, I have used the <strong>!important</strong> flag to make my work easier.</p>
<p>All the customizations you see below override only a handful of CSS styles. The rest are inherited by the default stylesheet.<strong> Let&#8217;s begin!</strong></p>
<p>The first thing we will do in <strong>styles.css</strong>, after styling the page itself, is to change the backgrounds of the timeline:</p>
<pre class="brush:css">#timeline{
	background:none;
}

/* The individual events in the slider */
.slider .slider-container-mask .slider-container{
	background:none;
}

/* Setting a custom background image */
#timeline div.navigation{
    background: url('../img/timeline_bg.jpg') repeat;
    border-top:none;
}</pre>
<div id="attachment_1932" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2012/04/timeline-portfolio/"><img class="size-full wp-image-1932" title="Timeline Navigation with a CSS 3D Effect" src="http://cdn.tutorialzine.com/wp-content/uploads/2012/03/a-css-3d-effect.jpg" alt="Timeline Navigation with a CSS 3D Effect" width="620" height="260" /></a><p class="wp-caption-text">Timeline Navigation with a CSS 3D Effect</p></div>
<p>To create the 3D effect of the timeline navigation, we will need to use additional elements. But the Timeline plugin doesn&#8217;t include such in its markup. An easy solution is to use <strong>:before</strong> / <strong>:after</strong> pseudo elements. The :after element is the darker top part and it uses a linear gradient to enhance the effect.</p>
<pre class="brush:css">#timeline div.navigation:before{
	position:absolute;
	content:'';
	height:40px;
	width:100%;
	left:0;
	top:-40px;
	background: url('../img/timeline_bg.jpg') repeat;
}

#timeline div.navigation:after{
	position:absolute;
	content:'';
	height:10px;
	width:100%;
	left:0;
	top:-40px;
	background:repeat-x;

	background-image: linear-gradient(bottom, #434446 0%, #363839 100%);
	background-image: -o-linear-gradient(bottom, #434446 0%, #363839 100%);
	background-image: -moz-linear-gradient(bottom, #434446 0%, #363839 100%);
	background-image: -webkit-linear-gradient(bottom, #434446 0%, #363839 100%);
	background-image: -ms-linear-gradient(bottom, #434446 0%, #363839 100%);
}</pre>
<p>Then we add a dark background to the timeline navigation (the section with the small clickable tooltips that represent the events):</p>
<pre class="brush:css">#timeline div.timenav-background{
 	background-color:rgba(0,0,0,0.4) !important;

}

#timeline .navigation .timenav-background .timenav-interval-background{
	background:none;
}

#timeline .top-highlight{
	background-color:transparent !important;
}</pre>
<p>Later we style the zoom-in / zoom-out buttons and toolbar:</p>
<pre class="brush:css">#timeline .toolbar{
	border:none !important;
	background-color: #202222 !important;
}

#timeline .toolbar div{
	border:none !important;
}</pre>
<p>The numeric scale at the bottom comes next:</p>
<pre class="brush:css">#timeline .navigation .timenav .time .time-interval-minor .minor{
	margin-left:-1px;
}

#timeline .navigation .timenav .time .time-interval div{
	color: #CCCCCC;
}</pre>
<p>The previous and next arrows:</p>
<pre class="brush:css">.slider .nav-previous .icon {
	background: url("timeline.png") no-repeat scroll 0 -293px transparent;
}

.slider .nav-previous,.slider .nav-next{
	font-family:'Segoe UI',sans-serif;
}

.slider .nav-next .icon {
	background: url("timeline.png") no-repeat scroll 72px -221px transparent;
	width: 70px !important;
}

.slider .nav-next:hover .icon{
	position:relative;
	right:-5px;
}

.slider .nav-previous:hover, .slider .nav-next:hover {
    color: #666;
    cursor: pointer;
}

#timeline .thumbnail {
	border: medium none;
}</pre>
<p>The loading screen:</p>
<pre class="brush:css">#timeline .feedback {
	background-color: #222222;
	box-shadow: 0 0 30px rgba(0, 0, 0, 0.2) inset;
	border:none;
}

#timeline .feedback div{
	color: #AAAAAA;
	font-size: 14px !important;
	font-weight: normal;
}</pre>
<p>Then we move on to the slides:</p>
<pre class="brush:css">#timeline .slider-item h2,
#timeline .slider-item h3{
	font-family:'Antic Slab','Segoe UI',sans-serif;
}

#timeline .slider-item h2{
	color:#fff;
}

#timeline .slider-item p{
	font-family:'Segoe UI',sans-serif;
}

#timeline .slider-item img,
#timeline .slider-item iframe{
	border:none;
}</pre>
<p>Finally, we will customize the appearance of the front page. I am using <strong>nth-child(1)</strong> to target only the first slider-item, which contains the name and description of the timeline which have been defined in the JSON data source.</p>
<pre class="brush:css">/* Customizing the first slide - the cover */

#timeline .slider-item:nth-child(1) h2{
	font:normal 70px/1 'Antic Slab','Segoe UI',sans-serif;
	background:rgba(0,0,0,0.3);
	white-space: nowrap;
	padding:10px 5px 5px 20px;
	position:relative;
	right:-60px;
	z-index:10;
}

#timeline .slider-item:nth-child(1) p i{
	font:normal normal 40px 'Dancing Script','Segoe UI',sans-serif;
	background:rgba(0,0,0,0.3);
	white-space: nowrap;
	padding:5px 20px;
	position:relative;
	right:-60px;
	z-index:10;
}

#timeline .slider-item:nth-child(1) p .c1{
	color:#1bdff0;
}

#timeline .slider-item:nth-child(1) p .c2{
	color:#c92fe6;
}

#timeline .slider-item:nth-child(1) .media-container {
	left: -30px;
	position: relative;
	z-index: 1;
}

#timeline .slider-item:nth-child(1) .credit{
	text-align: center;
}</pre>
<p>The only thing left is to open up <em>timeline.psd</em> that is bundled with the download of the plugin, and change the color of some of the icons in photoshop. I have included the necessary files in the zip download for this tutorial. With this our timeline portfolio is complete!</p>
<h3>Done!</h3>
<p>You can use this portfolio to display not only your recent projects, but also interests and important moments of your career. Share your thoughts and suggestions in the comment section.</p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2012/04/timeline-portfolio/feed/</wfw:commentRss>
		<slash:comments>74</slash:comments>
		</item>
		<item>
		<title>Making a Flickr-powered Slideshow</title>
		<link>http://tutorialzine.com/2011/02/flickr-api-slideshow-jquery/</link>
		<comments>http://tutorialzine.com/2011/02/flickr-api-slideshow-jquery/#comments</comments>
		<pubDate>Mon, 21 Feb 2011 13:28:24 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1377</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2011/02/flickr-api-slideshow-jquery/"><img src="http://cdn.tutorialzine.com/img/featured/1377.jpg" /></a></div> In this tutorial we will be developing a jQuery plugin that will make it possible to create slideshows, product guides or presentations from your Flickr photo sets.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2011/02/flickr-api-slideshow-jquery/"><img src="http://cdn.tutorialzine.com/img/featured/1377.jpg" /></a></div> <p>Today we will be developing a jQuery plugin that will make it easy to create slideshows, product guides or presentations from your Flickr photo sets. The plugin will be using Flickr&#8217;s APIs and YQL to fetch the photos in the sets, after which it will create the markup of the slideshow and listen for events.</p>
<blockquote class="note"><p><strong>Updated on Oct <strong>11th </strong>2011:</strong> Due to a change in Flickr&#8217;s API, you are now required to provide an API key when requesting the photos in a set. The script and this tutorial were updated to reflect this change. If you have downloaded this script before, replace jqFlick.js and script.js. You will also need to generate a Flickr API key (as explained in the tutorial) and paste it in script.js.</p></blockquote>
<h3>The HTML</h3>
<p>Before starting with <strong><em>jqFlick</em></strong> (the name of our plugin), lest first lay down the HTML structure of the underlying document. I am including the plugin&#8217;s CSS stylesheet &#8211; <em><strong>jqFlick.css</strong></em>, which we will be creating in the next step, and the plugin&#8217;s js file &#8211; <em><strong>jqFlick.js</strong></em>.</p>
<h4>index.html</h4>
<pre class="brush:html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
&lt;title&gt;jqFlick - Flickr Micro Slider Plugin | Tutorialzine Demo&lt;/title&gt;

&lt;link rel="stylesheet" type="text/css" href="assets/css/styles.css" /&gt;
&lt;link rel="stylesheet" type="text/css" href="assets/jqFlick/jqFlick.css" /&gt;

&lt;/head&gt;
&lt;body&gt;

&lt;div id="page"&gt;

	&lt;h1&gt;Flickr Powered Micro Slider&lt;/h1&gt;

	&lt;div id="flickrSlider"&gt;&lt;/div&gt;

	&lt;p class="demos"&gt;More demos: &lt;select&gt;
    	&lt;option value="1" selected&gt;Presentation Example&lt;/option&gt;
        &lt;option value="2"&gt;Photo Slideshow&lt;/option&gt;
        &lt;option value="3"&gt;Product Shots (small)&lt;/option&gt;
    &lt;/select&gt;&lt;/p&gt;

&lt;/div&gt;

&lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"&gt;&lt;/script&gt;
&lt;script src="assets/jqFlick/jqFlick.js"&gt;&lt;/script&gt;
&lt;script src="assets/js/script.js"&gt;&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Additionally, we have <em>styles.css</em>, which styles the page itself, and script.js, which calls the plugin. Also, we have a select element with demos of three different configurations of the plugin. We will come back to this in a moment.</p>
<p>The other important element in the fragment above is the <em><strong>#flickrSlider</strong></em> div, which is going to be populated with the slider&#8217;s HTML by the <em>jqFlick</em> plugin:</p>
<h4>Generated Code</h4>
<pre class="brush:html">&lt;div id="flickrSlider" class="flickrSliderHolder" style="width: 500px; height: 345px;"&gt;
	&lt;span class="caption"&gt;&lt;/span&gt;
	&lt;ul style="width: 1000px; height: 320px; left: 0px;"&gt;
		&lt;li style="background-image: url('example.jpg'); width: 500px;"&gt;&lt;/li&gt;
		&lt;li style="background-image: url('example2.jpg'); width: 500px;"&gt;&lt;/li&gt;
	&lt;/ul&gt;
	&lt;div class="arrows"&gt;
		&lt;a class="previous" href="#"&gt;&lt;/a&gt;
		&lt;a class="next" href="#"&gt;&lt;/a&gt;
	&lt;/div&gt;
&lt;/div&gt;</pre>
<p>The <strong><em>#flickrSlider</em></strong> div is assigned a class name &#8211; <em>.flickrSliderHolder</em>, a width and a height. Inside it we have an unordered list with the slides, an arrow div holder with previous and next arrows, and a span for the captions. The unordered list is set to be wide enough to accommodate the LIs side by side. The slide animation is achieved by animating the left property of the UL.</p>
<div id="attachment_1381" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2011/02/flickr-api-slideshow-jquery/"><img class="size-full wp-image-1381" title="Flickr Slideshow jQuery Plugin" src="http://cdn.tutorialzine.com/wp-content/uploads/2011/02/flickr-slideshow-gallery-jquery-plugin.jpg" alt="Flickr Slideshow jQuery Plugin" width="620" height="460" /></a><p class="wp-caption-text">Flickr Slideshow jQuery Plugin</p></div>
<h3>The CSS</h3>
<p>We need to provide the plugin with its own stylesheet, so it is easier to include into a website. This stylesheet must only affect the markup generated by the plugin, and we have to make sure it does not corrupt any other elements on the page. To achieve this, we are going to prefix the styles with the <em>.flickrSliderHolder</em> class name, assigned to the slideshow holder by the plugin.</p>
<h4>jqFlick.css</h4>
<pre class="brush:css">.flickrSliderHolder{
	position:relative;
	overflow:hidden;
}

.flickrSliderHolder ul{
	position:absolute;
	height:100%;
	list-style:none;
}

.flickrSliderHolder ul li{
	float:left;
	height:100%;
	background-repeat:no-repeat;
	background-position:center center;
}

.flickrSliderHolder .arrows{
	position:absolute;
	right:0;
	bottom:0;
}

.flickrSliderHolder .arrows a{
	width:22px;
	height:22px;
	float:left;
	background:url('arrows.png') no-repeat top left;
	text-decoration:none;
	outline:none;
	border:none;
}

.flickrSliderHolder a.previous:hover{
	background-position:left bottom;
}

.flickrSliderHolder a.next{
	margin-left:-1px;
	background-position:top right;
}

.flickrSliderHolder a.next:hover{
	background-position:bottom right;
}

.flickrSliderHolder .caption{
	font-size:13px;
	line-height: 22px;
	position:absolute;
	bottom:0;
	left:0;
}</pre>
<p>Once called, <em>jqFlick</em> assigns the <em>.flickrSliderHolder</em> class to the slider holder div, and generates the markup that we saw in the previous step. The code above styles the arrows, caption, unordered list and the container.</p>
<div id="attachment_1382" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2011/02/flickr-api-slideshow-jquery/"><img class="size-full wp-image-1382" title="Perfect for Slideshows, Product Guides and Presentations" src="http://cdn.tutorialzine.com/wp-content/uploads/2011/02/perfect-slideshows-product-guides-presentations.jpg" alt="Perfect for Slideshows, Product Guides and Presentations" width="620" height="260" /></a><p class="wp-caption-text">Perfect for Slideshows, Product Guides and Presentations</p></div>
<h3>The jQuery Code</h3>
<p>Starting with the jQuery section, lets first see what a response from the Flickr API looks like:</p>
<h4>Sample YQL Response</h4>
<pre class="brush:js">{
    "query": {
        "count": 3,
        "created": "2011-02-19T20:11:18Z",
        "lang": "en-US",
        "results": {
            "photo": [{
                "farm": "6",
                "id": "5456788328",
                "isprimary": "1",
                "secret": "e9eddccf8e",
                "server": "5213",
                "title": "The title of the image becomes an optional caption."
            }, {
                "farm": "6",
                "id": "5456179165",
                "isprimary": "0",
                "secret": "28bae85307",
                "server": "5216",
                "title": "There are no limits really."
            }, {
                "farm": "6",
                "id": "5456179233",
                "isprimary": "0",
                "secret": "e05287691f",
                "server": "5018",
                "title": "What more do you need.."
            }]
        }
    }
}</pre>
<p>Here I&#8217;ve selected the photos that are contained in <a href="http://www.flickr.com/photos/59645888@N08/sets/72157625956932639/" target="_blank">this photoset</a>. The response contains useful information about the images. We are going to use the farm, id, secret, and server properties of these objects to put together the URL at which the photos are located, while the title properties are going to be used as captions.</p>
<p>You can find your photos at the following address, by replacing the keywords with the objects&#8217; values:</p>
<pre class="brush:plain">http://farm{FARM}.static.flickr.com/{SERVER}/{ID}_{SECRET}.jpg</pre>
<p>In our plugin, we will be using Flickr&#8217;s API method for <a href="http://www.flickr.com/services/api/flickr.photosets.getPhotos.htm" target="_blank">listing photos in a photoset</a>. However, to communicate with Flickr&#8217;s APIs, we will need to register for an API key.</p>
<h4>API key registration</h4>
<p>This step is actually quite simple. You need to have a valid Flickr registration and visit <a href="http://www.flickr.com/services/apps/create/" target="_blank">this page</a>. After you choose the type of the registration (non commercial in our case), you fill in the application details. You now get your API key, which you will need in a second.</p>
<blockquote class="note"><p>For more info on the various Flickr APIs you can go to their <a href="http://www.flickr.com/services/api/" target="_blank">documentation page</a>. If you would like to know more about the URL addresses of their photos (including info on how to fetch different image sizes) see <a href="http://www.flickr.com/services/api/misc.urls.html" target="_blank">here</a>. You can also read more about YQL in our previous <a href="../?s=YQL">YQL tutorials.</a></p></blockquote>
<p>Now we are ready to write the jQuery code. As you know, encapsulating jQuery functionality in a plugin has many benefits, as you can read from our <a href="http://tutorialzine.com/2011/02/converting-jquery-code-plugin/">jQuery plugin tutorial</a>. Lets see what jqFlick.js, the main plugin file, looks like:</p>
<h4>jqFlick.js</h4>
<pre class="brush:js">(function($){

	$.fn.jqFlick = function(options){

		// Default options:

		options = $.extend({
			width:500,
			height:500,
			maxFetch:50,
			captions:false,
			autoAdvance:false,
			advancePeriod:5000,
			apiKey:''
		},options);

		// Using YQL and the flickr.photosets.photos table to query the Flickr API.

		var YQL = 'http://query.yahooapis.com/v1/public/yql?q={QUERY}&amp;format=json&amp;callback=?',
			query = "SELECT * FROM flickr.photosets.photos({MAX}) WHERE photoset_id='{PHOTOSET}'"+
				" AND api_key='{KEY}'";

		// Replacing the "{EXAMPLE}" keywords from the strings:

		YQL = templateReplace(YQL,{
			"query": encodeURIComponent(
				templateReplace(query,{
					photoset : options.photosetID,
					max	: options.maxFetch,
					key	: options.apiKey
				}
			))
		});

		// Template for building Flickr's image URLs:

		var flickrSRC = 'http://farm{FARM}.static.flickr.com/{SERVER}/{ID}_{SECRET}.jpg',
			flickrSlider = this;

		flickrSlider.trigger('jqFlickRemove');

		// Fetching the images using Flickr's API:

		$.getJSON(YQL,function(r){
			if(!r || !r.query || !r.query.count){
				throw "There is no such photoset!";
			}

			var currentPos = 1,
				cnt = r.query.count;

			var caption = $('&lt;span&gt;',{
				className: 'caption'
			}).appendTo(flickrSlider);

			var ul = $('&lt;ul&gt;',{
				css:{
					width: options.width*r.query.count,
					height:options.height
				}
			});

			// Looping through the photo results:

			$.each(r.query.results.photo,function(){
				data = this;

				// Creating a new LI element with the photo as its
				// centered background image:

				$('&lt;li&gt;',{
					css : {
						backgroundImage: 'url('+templateReplace(flickrSRC,data)+')',
						width: options.width
					}
				}).appendTo(ul);
			});

			flickrSlider.addClass('flickrSliderHolder')
						.width(options.width)
						.height(options.height+25)
						.append(ul);

			// Binding a custom "slide" event.
			// You can then flickrSlider.trigger("slide",2)
			// to go to the second slide:

			flickrSlider.bind('slide',function(e,slide){
				if(slide &lt; 1 || slide &gt; cnt || ul.is(':animated')){
					return false;
				}

				ul.animate({
					left:-(slide-1)*options.width
				},{
					easing: 'easeInOutCirc',
					duration: 300
				});

				if(options.captions){

					// Animating the transition between
					// the captions (if enabled):

					caption.fadeOut(150,function(){
						caption.html(r.query.results.photo[slide-1].title);
					}).fadeIn(150);
				}

				currentPos = slide;
			});

			var arrows = $('&lt;div&gt;',{
				className: 'arrows'
			});

			// Creating the previous / next arrows, and
			// binding event listeners for the click events:

			var arrowPrev = $('&lt;a&gt;',{
				className: 'previous',
				href: '#',
				click : function(){
					var toShow = currentPos - 1;
					if(toShow &lt; 1){
						toShow = cnt;
					}

					flickrSlider.trigger('slide',[toShow]);
					return false;
				}
			}).appendTo(arrows);

			var arrowNext = $('&lt;a&gt;',{
				className: 'next',
				href: '#',
				click : function(){
					var toShow = currentPos + 1;
					if(toShow &gt; cnt){
						toShow = 1;
					}

					flickrSlider.trigger('slide',[toShow]);
					return false;
				}
			}).appendTo(arrows);

			arrows.appendTo(flickrSlider);

			// Showing the first slide by default:

			flickrSlider.trigger('slide',[1]);

			if(options.autoAdvance){

				// If auto advance is enabled, listen for
				// the load event and schedule a periodic slide change.
				//
				// Read more here:
				// http://tutorialzine.com/2011/01/how-to-make-auto-advancing-slideshows/

				$(window).load(function(){

					$.fn.jqFlick.timeOut = null;

					arrowPrev.add(arrowNext).click(function(e,simulated){
						if(!simulated){
							clearTimeout($.fn.jqFlick.timeOut);
						}
					});

					(function autoAdvance(){
						if($.fn.jqFlick.timeOut){
							arrowNext.trigger('click',[true]);
						}
						$.fn.jqFlick.timeOut = setTimeout(autoAdvance,options.advancePeriod);
					})();
				});
			}
		});

		// This custom event removes all event listeners,
		// and empties the slider holder:

		flickrSlider.bind('jqFlickRemove',function(){
			if($.fn.jqFlick.timeOut){
				clearTimeout($.fn.jqFlick.timeOut);
			}

			flickrSlider.empty().unbind('jqFlickRemove slide');

		});

		return flickrSlider;

	};

	// Helper function for replacing "{KEYWORD}" with
	// the respectful values of an object:

	function templateReplace(template,data){
		return template.replace(/{([^}]+)}/g,function(match,group){
			return data[group.toLowerCase()];
		});
	}

	// A custom easing functon. For more info visit:
	// http://gsgd.co.uk/sandbox/jquery/easing/

	$.easing.easeInOutCirc = function (x, t, b, c, d) {
		if ((t/=d/2) &lt; 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
	};

})(jQuery);</pre>
<p><em>jqFlick</em> takes an options object as its only parameter. You are required to specify the id of the photoset (the <em>photosetID </em>property), which you can easily copy from the address bar of your web browser while viewing the photoset. Only public photosets can be shown by the <em>jqFlick</em>.</p>
<p>Now lets see how the plugin is called. At the top of this file, you will need to paste your Flickr API key that we generated above:</p>
<h4>js/script.js</h4>
<pre class="brush:js">$(document).ready(function(){

	// Paste your Flickr API key here
	var apiKey = '';

	// Creating a flickr slider. This is
	// how you would probably use the plugin.

	$('#flickrSlider').jqFlick({
		photosetID: '72157625956932639',
		width:500,
		height:320,
		autoAdvance:true,
		apiKey:apiKey
	});

	// Creating different flickr sliders,
	// depending on the select element value.

	$('select').change(function(){

		var options = {};

		switch(this.value){
			case '1':
				options = {
					photosetID: '72157625956932639',
					width:500,
					height:320,
					captions:true,
					autoAdvance:true,
					apiKey:apiKey
				};
				break;
			case '2':
				options = {
					photosetID:'42296',
					width:500,
					height:500,
					captions:true,
					autoAdvance:true,
					apiKey:apiKey
				};
				break;
			case '3':
				options = {
					photosetID:'72157625961099915',
					width:200,
					height:150,
					apiKey:apiKey
				}
		}

		$('#flickrSlider').jqFlick(options);
	});

});</pre>
<p>In the switch statement above, I am listening for the change event of the select dropdown. There, depending on the value of the select, I assign different options objects, which are then passed to the plugin. This demonstrates the different options that are available without taking much screen space.</p>
<p><strong>With this our Flickr-powered Slideshow is complete!</strong></p>
<h3>Conclusion</h3>
<p>You can use this plugin to build slideshows, product guides or presentations. To use the plugin you just need to drop the jqFlickr folder to your website root and include jqFlick.css and jqFlick.js in your HTML documents.</p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2011/02/flickr-api-slideshow-jquery/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Dynamic FAQ Section w/ jQuery, YQL &amp; Google Docs</title>
		<link>http://tutorialzine.com/2010/08/dynamic-faq-jquery-yql-google-docs/</link>
		<comments>http://tutorialzine.com/2010/08/dynamic-faq-jquery-yql-google-docs/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 15:22:49 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1061</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/08/dynamic-faq-jquery-yql-google-docs/"><img src="http://cdn.tutorialzine.com/img/featured/1061.jpg" /></a></div> In this tutorial, we are making a dynamic FAQ section. The script, with the help of jQuery &#038; YQL, will pull the contents of a shared spreadsheet in your Google Docs account, and use the data to populate the FAQ section with content.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2010/08/dynamic-faq-jquery-yql-google-docs/"><img src="http://cdn.tutorialzine.com/img/featured/1061.jpg" /></a></div> <p>In this tutorial, we are making a dynamic FAQ section. The script, with the help of jQuery &amp; <a href="http://developer.yahoo.com/yql/" target="_blank">YQL</a>, will pull the contents of a shared spreadsheet in your Google Docs account, and use the data to populate the FAQ section with questions and answers.</p>
<p>The best aspect of this solution, is that you can change the contents of  the FAQ section from within Google Docs &#8211; just edit the spreadsheet.  You can even leverage the rest of Google Docs&#8217; features, such as  collaborative editing. This way, a small team can support the FAQ  section without the need of a dedicated CMS solution.</p>
<p><em>Thanks to <a href="http://csi.nfshost.com/goodies/" target="_blank">Chris Ivarson</a> for designing the Google Docs icon, used in the featured illustration of this tutorial.</em></p>
<h3>Google Docs</h3>
<p>Before starting work on the FAQ section, we first need to create a new Google Docs Spreadsheet. As you probably already have an account with Google (if not, <a href="https://docs.google.com/">create one</a>), we&#8217;ll move straight to the interesting part.</p>
<p>In a blank spreadsheet, start filling in two columns of data. The first column should contain the questions, and the second one the answers, that are going to become entries in your FAQ section. Each FAQ goes on a separate line. You can see the one that I created <a href="https://spreadsheets.google.com/ccc?key=0Ahe1-YRnPKQ_dEI0STVPX05NVTJuNENhVlhKZklNUlE&amp;hl=en&amp;authkey=CJiB3agC" target="_blank">here</a>.</p>
<p>After this, click <strong>Share &gt; Publish as webpage</strong> and choose CSV from the dropdown list. This will generate a link to your spreadsheet in the form of a regular CSV file, which we will use later.</p>
<h3>The HTML</h3>
<p>The first step in developing the script is the markup. The <strong>#page</strong> div is the main container element. It is the only div with an explicit width. It is also centered in the middle of the page with a <a href="http://tutorialzine.com/2010/03/centering-div-vertically-and-horizontally/">margin:auto</a>, as you will see in the CSS part of the tut.</p>
<h4>faq.html</h4>
<pre class="brush:html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;

&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;

&lt;/head&gt;

&lt;body&gt;

&lt;div id="page"&gt;

    &lt;div id="headingSection"&gt;
    	&lt;h1&gt;Frequently Asked Questions&lt;/h1&gt;
        &lt;a class="button expand" href="#"&gt;Expand&lt;/a&gt;
    &lt;/div&gt;

    &lt;div id="faqSection"&gt;
    	&lt;!-- The FAQs are inserted here --&gt;
    &lt;/div&gt;

&lt;/div&gt;

&lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"&gt;&lt;/script&gt;
&lt;script src="script.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>The stylesheet is included in the head of the document, and the jQuery library and our <strong>script.js</strong> are included at the bottom. All of these are discussed in detail in the next sections of this tutorial.</p>
<p>The <strong>#headingSection</strong> contains the h1 heading, and the expand/collapse button. After it comes the <strong>#faqSection</strong> div, where the FAQ entries are inserted after jQuery fetched the contents of your Google Docs Spreadsheet.</p>
<p>The FAQ entries are organized as a definition list structure (<strong>dl</strong>). This is one of the least used HTML elements, but is perfect for our task. Here is how it looks once jQuery adds it to the page.</p>
<h4>faq.html</h4>
<pre class="brush:html">&lt;dl&gt;
    &lt;dt&gt;&lt;span class="icon"&gt;&lt;/span&gt;How does this FAQ section work?&lt;/dt&gt;
    &lt;dd&gt;With the help of jQuery and YQL, this script pulls the latest data ..&lt;/dd&gt;

    &lt;dt&gt;&lt;span class="icon"&gt;&lt;/span&gt;Can you modify it?&lt;/dt&gt;
    &lt;dd&gt;This is the best part of it - you can change the contents ..&lt;/dd&gt;
&lt;/dl&gt;</pre>
<p>The <strong>dl</strong> element holds a <strong>dt</strong> for each question and a <strong>dd</strong> for each answer. The dd elements are hidden with display:none, and are only shown with a <strong>slideDown</strong> animation once the respective <strong>dt</strong> is clicked.</p>
<div id="attachment_1066" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/08/dynamic-faq-jquery-yql-google-docs/faq.html"><img class="size-full wp-image-1066" title="Dynamic FAQ Section" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/08/21.jpg" alt="Dynamic FAQ Section" width="620" height="460" /></a><p class="wp-caption-text">Dynamic FAQ Section</p></div>
<h3>The CSS</h3>
<p>The styles, (held in styles.css) are pretty straightforward and self-explanatory. As mentioned above, only the <strong>#page</strong> div, which acts as the main container, is explicitly assigned a width. It is also centered in the middle of the page with an auto value for the left/right margins.</p>
<h4>styles.css &#8211; Part 1</h4>
<pre class="brush:css">#page{
	width:753px;
	margin:50px auto;
}

#headingSection{
	background-color:#7b8b98;
	padding:40px;
	padding-left:60px;
	position:relative;
	border:1px solid #8b9ba7;
	border-bottom:none;
}

#faqSection{
	background:url('img/faq_bg.jpg') repeat-y #fff;
	padding:20px 90px 60px 60px;
	border:1px solid white;
	text-shadow:1px 1px 0 white;
}

h1{
	color:#fff;
	font-size:36px;
	font-weight:normal;
}

/* The expand / collapse button */

a.button{
	background:url('img/buttons.png') no-repeat;
	width:80px;
	height:38px;
	position:absolute;
	right:50px;
	top:45px;
	text-indent:-9999px;
	overflow:hidden;
	border:none !important;
}

a.button.expand:hover{ background-position:0 -38px;}
a.button.collapse{ background-position:0 -76px;}
a.button.collapse:hover{ background-position:0 bottom;}
</pre>
<p>We are using a single anchor tag for both the expand and the collapse button, by assigning it either the <strong>expand</strong> or the <strong>collapse</strong> CSS class. These classes determine which parts of the background image are offset into view. The background image itself is four times the height of the button, and contains a normal and a hover state for both the expand and collapse button versions.</p>
<h4>styles.css &#8211; Part 2</h4>
<pre class="brush:css">/* Definition Lists */

dt{
	color:#8F9AA3;
	font-size:25px;
	margin-top:30px;
	padding-left:25px;
	position:relative;
	cursor:pointer;
	border:1px solid transparent;
}

dt:hover{ color:#5f6a73;}

dt .icon{
	background:url('img/bullets.png') no-repeat;
	height:12px;
	left:0;
	position:absolute;
	top:11px;
	width:12px;
}

dt.opened .icon{ background-position:left bottom;}

dd{
	font-size:14px;
	color:#717f89;
	line-height:1.5;
	padding:20px 0 0 25px;
	width:580px;
	display:none;
}
</pre>
<p>When a definition title (dt) is clicked, its respective dd is expanded into view (as you will see in the next section). With this, the dt is also assigned an <strong>opened</strong> class. This class helps jQuery determine which FAQ&#8217;s are opened, and in the same time affects the styling of the small bullet on the left of the title.</p>
<div id="attachment_1067" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/08/dynamic-faq-jquery-yql-google-docs/faq.html"><img class="size-full wp-image-1067" title="FAQ expanded" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/08/3.png" alt="FAQ expanded" width="620" height="260" /></a><p class="wp-caption-text">FAQ expanded</p></div>
<h3>The jQuery</h3>
<p>Moving to probably the most interesting part of the tutorial. If you&#8217;ve been following the tutorials on this site, you&#8217;ve probably noticed that <a href="http://developer.yahoo.com/yql/" target="_blank">YQL</a> finds its way into <a href="http://tutorialzine.com/?s=YQL">a lot of the tutorials here</a>. The main reason behind this, is that YQL makes possible for developers to use it as a proxy for a wide range of APIs, and implement a diverse functionality entirely in JavaScript.</p>
<p>Today we are using YQL to fetch our Google Spreadsheet as CSV and parse it, so that it is available as a regular JSON object. This way, we end up with a free and easy to update data storage for our simple app.</p>
<h4>script.js</h4>
<pre class="brush:js">$(document).ready(function(){

	// The published URL of your Google Docs spreadsheet as CSV:
	var csvURL = 'https://spreadsheets.google.com/pub?key='+
			'0Ahe1-YRnPKQ_dEI0STVPX05NVTJuNENhVlhKZklNUlE&amp;hl=en&amp;output=csv';

	// The YQL address:
	var yqlURL =	"http://query.yahooapis.com/v1/public/yql?q="+
			"select%20*%20from%20csv%20where%20url%3D'"+encodeURIComponent(csvURL)+
			"'%20and%20columns%3D'question%2Canswer'&amp;format=json&amp;callback=?";

	$.getJSON(yqlURL,function(msg){

		var dl = $('&lt;dl&gt;');

		// Looping through all the entries in the CSV file:
		$.each(msg.query.results.row,function(){

			// Sometimes the entries are surrounded by double quotes. This is why
			// we strip them first with the replace method:

			var answer = this.answer.replace(/""/g,'"').replace(/^"|"$/g,'');
			var question = this.question.replace(/""/g,'"').replace(/^"|"$/g,'');

			// Formatting the FAQ as a definition list: dt for the question
			// and a dd for the answer.

			dl.append('&lt;dt&gt;&lt;span class="icon"&gt;&lt;/span&gt;'+
			question+'&lt;/dt&gt;&lt;dd&gt;'+answer+'&lt;/dd&gt;');
		});

		// Appending the definition list:
		$('#faqSection').append(dl);

		$('dt').live('click',function(){
			var dd = $(this).next();

			// If the title is clicked and the dd is not currently animated,
			// start an animation with the slideToggle() method.

			if(!dd.is(':animated')){
				dd.slideToggle();
				$(this).toggleClass('opened');
			}

		});

		$('a.button').click(function(){

			// To expand/collapse all of the FAQs simultaneously,
			// just trigger the click event on the DTs

			if($(this).hasClass('collapse')){
				$('dt.opened').click();
			}
			else $('dt:not(.opened)').click();

			$(this).toggleClass('expand collapse');

			return false;
		});

	});
});</pre>
<p>It may not be clear from the code above, but jQuery sends a JSONP request to YQL&#8217;s servers with the following YQL query:</p>
<pre class="brush:sql">SELECT * FROM csv
WHERE url='https://spreadsheets.google.com/...'
AND columns='question,answer'</pre>
<p><strong><em>CSV</em></strong> is a YQL table, which takes the URL of a csv file and a list of column names. It returns a JSON object with the column names as its properties. The script then filters them (stripping off unnecessary double quotes) and inserts them as a definition list (DL)  into the page.</p>
<p><strong>With this our dynamic FAQ section is complete!</strong></p>
<h3>Customization</h3>
<p>To use this script with your own spreadsheet, you only need to edit the csvURL variable in <strong>script.js</strong>, and replace it with the CSV  URL of your spreadsheet. You can obtain this address from <strong>Share &gt; Publish as webpage &gt; CSV dropdown</strong>. Also, be aware that when you make changes to the spreadsheet, it could take a few minutes for the changes to take effect. You can speed this up by clicking the <em><strong>Republish now</strong></em> button, found in the same overlay window.</p>
<div id="attachment_1065" class="wp-caption alignnone" style="width: 630px"><img class="size-full wp-image-1065" title="Obtaining the CSV URL" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/08/1.png" alt="Obtaining the CSV URL" width="620" height="460" /><p class="wp-caption-text">Obtaining the CSV URL</p></div>
<h3>Final Words</h3>
<p>You can use the same technique to power different kinds of dynamic pages. However, this implementation does have its shortcomings. All the content is generated with JavaScript, which means that it will not be visible to search engines.</p>
<p>To guarantee that your data will be crawled, you can take a different route. You could use PHP, or other back-end language, to fetch and display the data from YQL in a fixed interval of time &#8211; say 30 minutes (or even less frequently, if you don&#8217;t plan to update the data often).</p>
<p><strong>Be sure to share your suggestions in the comment section below.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/08/dynamic-faq-jquery-yql-google-docs/feed/</wfw:commentRss>
		<slash:comments>59</slash:comments>
		</item>
		<item>
		<title>Making Your First Google Chrome Extension</title>
		<link>http://tutorialzine.com/2010/06/making-first-chrome-extension/</link>
		<comments>http://tutorialzine.com/2010/06/making-first-chrome-extension/#comments</comments>
		<pubDate>Wed, 09 Jun 2010 12:53:55 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=940</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/06/making-first-chrome-extension/"><img src="http://cdn.tutorialzine.com/img/featured/940.jpg" /></a></div> In this tutorial, we are going to create a simple extension, which puts a small icon next to Chrome's address bar, and, when clicked, will fetch Tutorialzine's RSS feed and display a fancy preview of our latest tutorials.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2010/06/making-first-chrome-extension/"><img src="http://cdn.tutorialzine.com/img/featured/940.jpg" /></a></div> <p>The Google Chrome web browser is slowly growing in popularity. This is no surprise, as it is a great browser, and is backed by no other than Google. It also provides great tools for web developers and I find myself using it more and more (actually Firebug is the only thing keeping me from crossing to the other side).</p>
<p>With the introduction of <a href="https://chrome.google.com/extensions" target="_blank">extensions</a>, Google Chrome became even more agile and powerful.</p>
<p>In this tutorial, we are going to create a simple extension, which puts a small icon next to Chrome&#8217;s address bar, and, when clicked, will fetch Tutorialzine&#8217;s RSS feed and display a fancy preview of our latest tutorials.</p>
<p>[By the way, we just launched <a href="http://www.zinescripts.com/" target="_blank">ZineScripts</a>! Use this Promo Code for a <strong>10% discount</strong>: <em>google-chrome-tut-93a2</em>]</p>
<p>First a few words about extensions.</p>
<h3>How Extensions Work</h3>
<p>Extensions in Google Chrome are basically webpages. You have javascript files, stylesheets and images. You can even use JavaScript libraries like  jQuery.</p>
<p>The extensions are, however, treated a bit differently than your regular webpage, which is displayed in the browser. You can have access to all the opened tabs, to the user&#8217;s browsing history, you can manipulate all the pages that are opened, send AJAX requests to any website and much more.</p>
<p>You also have the benefit (or the limitation) that your extension runs only on one browser. You can forget all compatibility issues and embrace Google Chrome&#8217;s hot new HTML5 features.</p>
<div id="attachment_945" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/06/making-first-chrome-extension/demo.html"><img class="size-full wp-image-945" title="Tutorialzine's Google Chrome Extension" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/06/i11.png" alt="Tutorialzine's Google Chrome Extension" width="620" height="460" /></a><p class="wp-caption-text">Tutorialzine&#39;s Google Chrome Extension</p></div>
<h3>Developing extensions</h3>
<p>Extension  are packed in a <strong>.crx</strong> file (arenamed zip file) but during development, you can map your working folder as an extension. This way you can quickly change and deploy code without the need of repackaging.</p>
<p>This is done by opening the extension page (type <em><a href="chrome://extensions/">chrome://extensions/</a></em> in the address bar, or click <em>Wrench icon &gt; Extensions</em>), and clicking <strong>Developer mode &gt; Load unpacked extension..</strong> on the page. After you make a change to the extension, just hit the Reload link below it.</p>
<p>After you&#8217;re done developing, click <strong>Pack extension..</strong> and a crx file will be created for you. You can serve this file from your site and enable your site&#8217;s visitors to install it.</p>
<p>Google Chrome is by far the easiest browser to make extensions for, as you will see from the steps below.</p>
<p><strong>A note about debugging</strong>: To debug your extension, right-click on your extension&#8217;s icon, next to the address bar, and choose <em>Inspect popup</em>. You can also check out <a href="http://code.google.com/chrome/extensions/tut_debugging.html" target="_blank">this tutorial</a>.</p>
<h3>Step 1 &#8211; Manifest.json</h3>
<p>The first step in creating an extension, is mapping a folder on your hard drive as an extension (as explained the above). You are going to put all your files in this folder.</p>
<p>The only thing required from your extension by Chrome, is the <strong>manifest.json</strong> file. This is a text file, which holds configuration settings in the form of a json object.</p>
<p>Here is the one we are going to use:</p>
<h4>manifest.json</h4>
<pre class="brush:js">{
	"name": "Tutorialzine Extension",
	"version": "1.0",
	"description": "Making your first Google Chrome extension.",
	"browser_action":	{
		"default_icon": "icon.png",
		"popup": "tutorialzine.html"
	},

	"icons":{
		"128":"icon_128.png"
	}
}</pre>
<p>In this file we are specifying the name of the extension and a number of other options, such as browser actions and permissions.</p>
<p>In <strong>browser_actions</strong>, we put settings that are in relation with the browser window. The <strong>popup</strong> property tells Chrome, that we are going to show <em>tutorialzine.html</em> as a popup. There are a number of settings you can put in browser_actions. You can read more on <a href="http://code.google.com/chrome/extensions/browserAction.html" target="_blank">Google Chrome&#8217;s Extension documentation</a>.</p>
<p>For this extension we do not need access to currently opened pages, nor manipulating tabs and windows. If we needed those, however, we would need to include a permissions property, with the addresses of the pages.</p>
<p>For more information about the manifest file, refer to <a href="http://code.google.com/chrome/extensions/manifest.html" target="_blank">Google Chrome&#8217;s documentation</a>.</p>
<h3>Step 2 &#8211; HTML 5</h3>
<p>As mentioned above, we told Chrome that <em>tutorialzine.html</em> is going to be opened as a popup. This is a regular html file, complete with stylesheets and js files.</p>
<p>And as Google Chrome has a really good support for HTML5, we can code tutorialzine.html in it. You could, however, use any HTML version you normally code your sites with.</p>
<h4>tutorialzine.html</h4>
<pre class="brush:html">&lt;!DOCTYPE html&gt; &lt;!-- The new doctype --&gt;
&lt;html&gt;
&lt;head&gt; &lt;!-- No title and meta tags are necessary for the extension --&gt;

&lt;link rel="stylesheet" type="text/css" href="style.css" /&gt;
&lt;script src="jquery.min.js"&gt;&lt;/script&gt; &lt;!-- Including jQuery --&gt;
&lt;script src="script.js"&gt;&lt;/script&gt; &lt;!-- Our script file --&gt;

&lt;/head&gt;

&lt;body&gt;

&lt;h1&gt;Latest Tutorials on Tutorialzine&lt;/h1&gt;

&lt;div id="content"&gt;
&lt;!-- The latest tutorials are going to be inserted here --&gt;
&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>As you can see, we are addressing the css and js files directly. Chrome will include them for us. Just as if we are working on a regular webpage.</p>
<h3>Step 3 &#8211; CSS3</h3>
<p>As the extension is rendered Google Chrome, we do not need to limit ourselves with the least common denominator when it comes to CSS3 support. This is why we can afford to use fancy rules like <strong>-webkit-box-reflection</strong> and <strong>-webkit-gradient</strong>.</p>
<h4>styles.css &#8211; Part 1</h4>
<pre class="brush:css">*{
	margin:0;
	padding:0;
}

body{
	/* Setting default text color, background and a font stack */
	font-size:12px;
	color:#666;

	/* A webkit gradient: */
	background:-webkit-gradient(linear, 0% 0%, 0% 100%, from(#EEE), to(#DDD));

	text-shadow:1px 1px 0 white;
	font-family:Arial, Helvetica, sans-serif;
	overflow-x:hidden;
}

.tutorial{
	width:500px;
	padding:10px 20px;
	margin-bottom:10px;
}

img{
	width:100px;
	height:100px;
	float:left;

	/* Webkit CSS3 Reflection */
	-webkit-box-reflect: below 0 -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0.75, transparent), to(rgba(255, 255, 255, 0.3))) 0 0 0 0 stretch stretch;
}</pre>
<p><strong>-webkit-box-reflect</strong> creates a pure CSS reflection under the thumbnail images. It takes a number of parameters to generate the reflection &#8211; position of the reflection, offset from the bottom of the image, and a mask (which is defined with a gradient).</p>
<h4>styles.css &#8211; Part 2</h4>
<pre class="brush:css">p,a{
	padding:10px 0 0 120px;
	display:block;
}

a,a:visited{
	color:#09F;
	text-decoration:none;
}

a:hover{
	text-decoration:underline;
}

h1{
	/* Webkit gradient: */
	background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#EEE), to(#DDD));

	border-bottom: 1px solid #F0F0F0;
	font-size: 24px;
	font-weight: normal;
	margin-bottom: 30px;
	padding: 30px 0px;
	text-align: center;
	text-shadow: white 0px 1px 1px;
}

h2{
	font-size:24px;
	font-weight:normal;
	right:40px;
	padding-left:120px;
}

h1,h2{
	font-family:"Myriad Pro",Arial,Helvetica,sans-serif;
}</pre>
<p>In the second part of the code we are also using a gradient, but this time as a background for the h1 element.</p>
<div id="attachment_946" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/06/making-first-chrome-extension/demo.html"><img class="size-full wp-image-946" title="CSS3 Reflections &amp; Text Shadows" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/06/i21.png" alt="CSS3 Reflections &amp; Text Shadows" width="620" height="260" /></a><p class="wp-caption-text">CSS3 Reflections &amp; Text Shadows</p></div>
<h3>Step 4 &#8211; jQuery</h3>
<p>The JavaScript is executed as if it was part of a regular web page. This means that we can include the jQuery library and define a <strong>$(document).ready()</strong> function as we would normally do in a web project.</p>
<p>Clicking the extension icon has the same effect for the scripts on the page, as opening the page in a browser.</p>
<p>Inside $(document).ready(), we fetch the latest results from Tutorialzine&#8217;s RSS feed, with the help of <strong>Yahoo&#8217;s YQL API</strong>. We&#8217;ve used this API a <a href="http://tutorialzine.com/?s=YQL" target="_blank">couple of times before</a>, here on Tz. It allows us to use an SQL-like syntax to fetch data in a JSON format.</p>
<p>After fetching the data, we generate the HTML markup and include it in <em>tutorialzine.html</em>. We also save it to <strong>localStorage</strong> as a simple caching solution. localStorage is a simple way to save persistent data (it survives between page loads). This makes the experience of using the extension a lot faster.</p>
<h4>script.js</h4>
<pre class="brush:js">$(document).ready(function(){

	var query = "SELECT * FROM feed WHERE url='http://feeds.feedburner.com/Tutorialzine' LIMIT 2";

	// Storing the seconds since the epoch in now:
	var now = (new Date()).getTime()/1000;

	// If there is no cache set in localStorage, or the cache is older than 1 hour:
	if(!localStorage.cache || now - parseInt(localStorage.time) &gt; 1*60*60)
	{
		$.get("http://query.yahooapis.com/v1/public/yql?q="+encodeURIComponent(query)+"&amp;format=json&amp;callback=?",function(msg){

			// msg.query.results.item is an array:
			var items = msg.query.results.item;
			var htmlString = "";

			for(var i=0;i&lt;items.length;i++)
			{
				var tut = items[i];

				// Extracting the post ID from the permalink:
				var id = tut.guid.content.match(/(\d+)$/)[0];

				// Looping and generating the markup of the tutorials:

				htmlString += '&lt;div class="tutorial"&gt;\
								&lt;img src="http://cdn.tutorialzine.com/img/posts/'+id+'.jpg" /&gt;\
								&lt;h2&gt;'+tut.title+'&lt;/h2&gt;\
								&lt;p&gt;'+tut.description+'&lt;/p&gt;\
								&lt;a href="'+tut.link+'" target="_blank"&gt;Read more&lt;/a&gt;\
								&lt;/div&gt;';
			}

			// Setting the cache
			localStorage.cache	= htmlString;
			localStorage.time	= now;

			// Updating the content div:
			$('#content').html(htmlString);
		},'json');
	}
	else{
		// The cache is fresh, use it:
		$('#content').html(localStorage.cache);
	}
});</pre>
<p>In localStorage we also store a timestamp. We use it to determine how old the cache in localStorage is. If it is older than an hour, we ignore it and fetch the data again.</p>
<p>Here is a sample of the data that is returned from YQL.</p>
<pre class="brush:js">{
	"query": {
		"count": "1",
		"created": "2010-06-09T12:02:33Z",
		"lang": "en-US",
		"results": {

			"item": {
				"title": "Neon Text Effect With jQuery &amp; CSS",
				"link": "http://feedproxy.google.com/..",

				"comments": [
					"http://tutorialzine.com/2010/06/neon-text-effect..",
					"11"
				],

				"pubDate": "Tue, 01 Jun 2010 20:11:54 +0000",
				"creator": "Martin Angelov",

				"category": [
					"CSS",
					"jQuery"
				],

				"guid": {
					"isPermaLink": "false",
					"content": "http://tutorialzine.com/?p=925"
				},

				"description": "In this combined design and coding tutorial..",
				"commentRss": "http://tutorialzine.com/2010/06/neon-text-e..",
				"origLink": "http://tutorialzine.com/2010/06/neon-text-eff.."

			}
		}
	}
}
</pre>
<p>This structure is made available to us in the <strong>msg</strong> variable on line 11 of script.js.</p>
<p><strong>With this your first Google Chrome extension is complete!</strong></p>
<h3>Conclusion</h3>
<p>You can read more about extensions (including advanced features not covered in this tutorial) on <a href="http://code.google.com/chrome/extensions/overview.html" target="_blank">Google Chrome&#8217;s Extension documentation page</a>. I hope that this tutorial has given you a great start in extending the browser&#8217;s functionality.</p>
<p><strong>What do you think? Would you make a Chrome extension for your website?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/06/making-first-chrome-extension/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Combined Facebook, Twitter &amp; RSS Social Stats with jQuery, PHP &amp; YQL</title>
		<link>http://tutorialzine.com/2010/05/showing-facebook-twitter-rss-stats-jquery-yql/</link>
		<comments>http://tutorialzine.com/2010/05/showing-facebook-twitter-rss-stats-jquery-yql/#comments</comments>
		<pubDate>Wed, 19 May 2010 21:50:43 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=909</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/05/showing-facebook-twitter-rss-stats-jquery-yql/"><img src="http://cdn.tutorialzine.com/img/featured/909.jpg" /></a></div> This week we are going to create a simple widget, which combines the number of your RSS readers, twitter followers, and fans of your facebook fan page, to give a rough estimate of your social popularity.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2010/05/showing-facebook-twitter-rss-stats-jquery-yql/"><img src="http://cdn.tutorialzine.com/img/featured/909.jpg" /></a></div> <p>As we increasingly depend on more and more social services, there rises the need to provide a simple way to let our website visitors take part of our diverse social presence.</p>
<p>In this tutorial we are going to create a simple widget, which combines the number of your RSS readers, twitter followers, and fans of your facebook fan page, to give a rough estimate of your social popularity.</p>
<p>We are using jQuery and the <a href="http://code.drewwilson.com/entry/tiptip-jquery-plugin" target="_blank">tipTip plugin</a>, object-oriented PHP, and <a href="http://developer.yahoo.com/yql/" target="_blank">Yahoo&#8217;s YQL</a>, while demonstrating a number of interesting web development techniques.</p>
<blockquote class="note"><p><strong>Update</strong>: Facebook has made a minor change in their API which prevented this script from fetching the page fan count. This is now fixed and you can download the script again.</p></blockquote>
<h3>Step 1 &#8211; PHP</h3>
<p>YQL is a free Yahoo web service, which enables us to communicate  with numerous third-party APIs through a consistent SQL-like language (and hence the name). It is basically a gateway that sits between you and the other APIs.</p>
<p>This is especially important here, as we are using Yahoo&#8217;s YQL for  three very different tasks:</p>
<ul>
<li>Fetch your RSS subscriber count with FeedBurner&#8217;s <a href="http://code.google.com/apis/feedburner/awareness_api.html" target="_blank"> awareness API</a> (which comes in the form of an XML file that has to be parsed).<strong><br />
Note: </strong><em>You have to enable the awareness API to use this widget with your own feed. This is done from the Publicize Tab on your feed settings page</em>;</li>
<li>Use twitter&#8217;s API to get your number of followers;</li>
<li>Use Facebook&#8217;s new <strong>Graph API</strong> (<a href="http://developers.facebook.com/docs/api" target="_blank">link</a>) to get  information about the number of fans of your facebook fanpage.</li>
</ul>
<p>If it weren&#8217;t for YQL, we&#8217;d have to research and implement three very different solutions, which would slow us down significantly.</p>
<h4>includes/subscriber_stats.class.php</h4>
<pre class="brush:php">class SubscriberStats{

	public	$twitter,$rss,$facebook;
	public	$services = array();

	public function __construct($arr){

		$this-&gt;services = $arr;

		$yqlQueries = array();

		// Forming the Feedburner Awaraness API URL from the passed feed URL:
		$feedBurnerAwarenessAPI = 'http://feedburner.google.com/api/awareness'.
		'/1.0/GetFeedData?uri='.end(split('/',trim($arr['feedBurnerURL'],'/')));

		// Building an array with queries:

		if($arr['feedBurnerURL'])
			$yqlQueries[] = '
				SELECT * FROM xml
				WHERE url=\''.$feedBurnerAwarenessAPI.'\'
			';

		if($arr['twitterName'])
			$yqlQueries[] = '
				SELECT * FROM twitter.user.profile
				WHERE id=\''.$arr['twitterName'].'\'
			';

		if($arr['facebookFanPageURL'])
			$yqlQueries[] = '
			SELECT likes FROM facebook.graph
			WHERE id=\''.end(split('/',trim($arr['facebookFanPageURL'],'/'))).'\'
			';

		// Combing them into a YQL multiquery:
		$multiQuery =
		'SELECT * FROM query.multi WHERE queries = "'.join(';',$yqlQueries).'"';

		// Executing the query:
		$result = json_decode(
			file_get_contents('http://query.yahooapis.com/v1/public/yql?q='.
			urlencode($multiQuery).'&amp;format=json&amp;diagnostics=false&amp;'
			'amp;env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys')
		)-&gt;query-&gt;results-&gt;results;

		// The results from the queries are accessible in the $results array:

		$this-&gt;rss = $result[0]-&gt;rsp-&gt;feed-&gt;entry-&gt;circulation;
		$this-&gt;twitter = $result[1]-&gt;item-&gt;meta[5]-&gt;content;
		$this-&gt;facebook = $result[2]-&gt;json-&gt;fan_count;
	}

	public function generate(){

		$total = number_format($this-&gt;rss+$this-&gt;twitter+$this-&gt;facebook);

		echo '
			&lt;div class="subscriberStats"&gt;
				&lt;div class="subscriberCount"
				title="'.$total.'+ Total Social Media Followers"&gt;'.$total.'&lt;/div&gt;

				&lt;div class="socialIcon"
				title="'.number_format($this-&gt;rss).' RSS Subscribers"&gt;
					&lt;a href="'.$this-&gt;services['feedBurnerURL'].'"&gt;
					&lt;img src="img/rss.png" alt="RSS" /&gt;&lt;/a&gt;
				&lt;/div&gt;

				&lt;div class="socialIcon"
				title="'.number_format($this-&gt;facebook).' Fans on Facebook"&gt;
					&lt;a href="'.$this-&gt;services['facebookFanPageURL'].'"&gt;
					&lt;img src="img/facebook.png" alt="Facebook" /&gt;&lt;/a&gt;
				&lt;/div&gt;

				&lt;div class="socialIcon"
				title="'.number_format($this-&gt;twitter).' Twitter Followers"&gt;
				&lt;a href="http://twitter.com/'.$this-&gt;services['twitterName'].'"&gt;
					&lt;img src="img/twitter.png" alt="Twitter" /&gt;&lt;/a&gt;
				&lt;/div&gt;
			&lt;/div&gt;
		';
	}
}</pre>
<p>When we create an object of this class, the construct method is called, and a YQL query is created and executed.</p>
<p>To request the data from YQL&#8217;s servers, we just use <strong>file_get_contents()</strong> with the query passed as a parameter of the URL address. This returns a JSON object (basically a JavaScript object) which we can decode into a native PHP array with the in-build <strong>json_decode()</strong> function.</p>
<p>The results of these queries are saved locally and are made available for use in the <strong>generate()</strong> method which renders all the needed markup.</p>
<p>And now lets see how this class is used:</p>
<h4>subscriber_count.php</h4>
<pre class="brush:php">require "includes/subscriber_stats.class.php";

$cacheFileName = "cache.txt";

// IMPORTANT: after making changes to this file (or the SubscriberStats class)
// remeber to delete cache.txt from your server, otherwise you wont see your changes.

// If a cache file exists and it is less than 6*60*60 seconds (6 hours) old, use it:

if(file_exists($cacheFileName) &amp;&amp; time() - filemtime($cacheFileName) &gt; 6*60*60)
{
	$stats = unserialize(file_get_contents($cacheFileName));
}

if(!$stats)
{
	// If no cache was found, fetch the subscriber stats and create a new cache:

	$stats = new SubscriberStats(array(
		'facebookFanPageURL'	=&gt; 'http://www.facebook.com/smashmag',
		'feedBurnerURL'			=&gt; 'http://feeds.feedburner.com/Tutorialzine',
		'twitterName'			=&gt; 'Tutorialzine'
	));

	// Serialize turns the object into a string,
	// which can later be restored with unserialize():

	file_put_contents($cacheFileName,serialize($stats));
}

//	You can access the individual stats like this:
//	$stats-&gt;twitter;
//	$stats-&gt;facebook;
//	$stats-&gt;rss;

//	Output the markup for the stats:

$stats-&gt;generate();</pre>
<p>Sending a query to YQL&#8217;s servers and receiving a response is a relatively slow process and would be unwise to request the same information on every page load (not to mention that we could get banned from the API for abuse).</p>
<p>This is why we implement a simple caching system. The idea is simple: if a cache file does not exist (or is older than 6 hours), connect to YQL, create a new cache file and output the XHTML markup. Otherwise, just read the cache and output directly. This way we send a request to the API only once every six hours which is perfect for any practical purposes.</p>
<div id="attachment_913" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/05/showing-facebook-twitter-rss-stats-jquery-yql/demo.html"><img class="size-full wp-image-913 " title="Combined Social Media Followers Count" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/05/i11.png" alt="Combined Social Media Followers Count" width="620" height="260" /></a><p class="wp-caption-text">Combined Social Media Followers Count</p></div>
<h3>Step 2 &#8211; XHTML</h3>
<p>As mentioned in the PHP section above, the generate() method renders all the XHTML markup used to display the stats. Here is what the generated code looks like:</p>
<h4>sample code</h4>
<pre class="brush:html">&lt;div class="subscriberStats"&gt;
    &lt;div class="subscriberCount"  title="25,382+ Total Social Media Followers&gt;25,382&lt;/div&gt;

    &lt;div class="socialIcon" title="5,921 RSS Subscribers"&gt;
        &lt;a href="http://feeds.feedburner.com/Tutorialzine"&gt;
        &lt;img alt="RSS" src="img/rss.png" /&gt;&lt;/a&gt;
    &lt;/div&gt;

    &lt;div class="socialIcon" title="16,813 Fans on Facebook"&gt;
        &lt;a href="http://www.facebook.com/smashmag"&gt;
        &lt;img alt="Facebook" src="img/facebook.png" /&gt;&lt;/a&gt;
    &lt;/div&gt;

    &lt;div class="socialIcon" title="2,648 Twitter Followers"&gt;
        &lt;a href="http://twitter.com/Tutorialzine"&gt;
        &lt;img alt="Twitter" src="img/twitter.png" /&gt;&lt;/a&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre>
<p>This code is fetched via AJAX and displayed on the page. Notice the title attributes. They are used as the contents of the fancy tooltips which are created by jQuery and the tipTip plugin, which we will discuss in a moment.</p>
<h3>Step 3 &#8211; CSS</h3>
<p>The CSS code is also quite simple and straightforward. The <strong>subscriberStats</strong> is the main outer div, inside it we have a number of <strong>.socialIcon</strong> divs and the <strong>subscrberCount</strong>.</p>
<h4>css/styles.css</h4>
<pre class="brush:css">.subscriberStats{
	height:35px;
	padding:5px;
	width:220px;
}

.socialIcon{
	float:left;
	height:32px;
	width:32px;
}

a img{
	border:none;
}

.subscriberCount{
	border-bottom:1px dotted #CCCCCC;
	color:#999999;
	float:left;
	font-size:28px;
	line-height:32px;
	margin-right:10px;
}

#main{
	height:100px;
	margin:140px auto 50px;
	position:relative;
	width:200px;
}</pre>
<p>All of these are floated to the left. Also notice that we disable the borders on the icon images on line 14, which are displayed by default and ruin your design.</p>
<h3>Step 4 &#8211; jQuery</h3>
<p>After including the jQuery library to the page, we just need to listen to the $(document).ready event, which is executed when all the markup of the page is accessible (this happens before things like images are loaded and comes earlier than the onload event).</p>
<h4>js/script.js</h4>
<pre class="brush:js">$(document).ready(function(){

	// Using the load AJAX method to fetch the subscriber markup
	// from subscriber_count.php:

	$('#main').load('subscriber_count.php',function(){

		// Once loaded, convert the title attributes to tooltips
		// with the tipTip jQuery plugin:

		$('.subscriberStats div').tipTip({defaultPosition:'top'});
	})

});</pre>
<p><strong>#main</strong> is the div where we want to insert the stats. This could be your sidebar or website header. The load method fetches the markup from <strong>suscriber_count.php</strong> and displays it on the page.  The callback function is called after this and all the div titles are replaced with fancy tooltips by the <em>tipTip plugin</em>.</p>
<p><strong>With this our combined social stats widget is complete!</strong></p>
<h3>Conclusion</h3>
<p>With services like YQL working with third party APIs is a charm. Not only it provides a common interface to a sea of technologies, but it also guarantees that you will be able to access to the services you want even as the underlying APIs change overtime.</p>
<p><strong>What do you think? How would you improve this code?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/05/showing-facebook-twitter-rss-stats-jquery-yql/feed/</wfw:commentRss>
		<slash:comments>42</slash:comments>
		</item>
		<item>
		<title>Making a Sleek Feed Widget With YQL, jQuery &amp; CSS3</title>
		<link>http://tutorialzine.com/2010/02/feed-widget-jquery-css-yql/</link>
		<comments>http://tutorialzine.com/2010/02/feed-widget-jquery-css-yql/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 16:08:21 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=661</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/02/feed-widget-jquery-css-yql/"><img src="http://cdn.tutorialzine.com/img/featured/661.jpg" /></a></div> We are making a sleek feed widget, that will fetch any feed and display it in your blog sidebar. You can set it up to show the latest posts from the different categories of your blog, your latest stumbles, or even people mentioning you on twitter.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2010/02/feed-widget-jquery-css-yql/"><img src="http://cdn.tutorialzine.com/img/featured/661.jpg" /></a></div> <p>You will be surprised at how much data is made available on the web through RSS or ATOM feeds &#8211; twitter searches, your latest diggs, Google Search alerts, your own blog categories and so much more. You just have to look for that orange icon and you&#8217;ll surely find a lot more precious data, just waiting to be put into use.</p>
<p>Today we are making a <strong>sleek feed widget</strong>, that will fetch any feed and display it in your blog sidebar. You can set it up to show the latest posts from the different categories of your blog, your latest stumbles, or even people mentioning you on twitter.</p>
<p><em>So go ahead, <strong>download the demo archive from the button above</strong>, and keep on reading..</em></p>
<h3>Problem Solving</h3>
<p>Before stepping into development, we have to clarify for ourselves what we are aiming for, discuss some potential problems, and their solutions.</p>
<h4>Problem 1 &#8211; Fetching Feeds</h4>
<p>The widget is entirely front-end based, so we have to find a way to fetch the feeds directly with JavaScript. AJAX is a great technology, but there are security restrictions that limit it to fetching data only from the current domain. This means we cannot access feeds directly and display them.</p>
<p>This is where <strong>YQL</strong> comes along. It fetches the feed we want, and makes it available to our script as a regular <strong>JSON</strong> object that we can later loop and print to the page.</p>
<blockquote><p>YQL is a free <strong>API</strong> service from Yahoo, with which you can do much more than just download feeds. It acts as a gateway between you and other API&#8217;s and lets you manipulate them with a quick to learn SQL-like syntax (hence the name).</p>
<p><span class="small">You can reed more about it in <a href="http://net.tutsplus.com/tutorials/other/an-api-for-the-web-learning-yql/" target="_blank">this tutorial on nettuts</a>, or go to the official <a href="http://developer.yahoo.com/yql/" target="_blank">YQL page</a>.</span></p></blockquote>
<p>Setting up YQL to work is tricky though (we have to dynamically include a <strong>&lt;script&gt;</strong> tag to the head section of the page, like we did in the <a href="http://tutorialzine.com/2009/10/jquery-twitter-ticker/">Twitter Ticker tutorial</a> few months back). Luckily, jQuery provides a method for just this purpose &#8211; <strong>getJSON</strong>. It does everything behind the scenes, so we don&#8217;t have to worry about the implementation.</p>
<h4>Problem 2 &#8211; Different Feed Formats</h4>
<p>As with everything else, feeds are available in a number of formats &#8211;  <strong>RSS1, RSS2</strong> and <strong>ATOM</strong>. They all have their differences and present a  challenge, because our code has to be able to loop through the results returned by <strong>YQL</strong> and successfully display the entries.</p>
<p>The solution to this is to move the functionality that displays the feeds in a separate function and use a number of logical <strong>OR</strong>-s ( || ) throughout the code. It works with all the feeds that I tested it with, but you could easily make your own version of the function for special cases (for example displaying Flickr streams with a thumbnail).</p>
<h4>Problem 3 &#8211; Insufficient Space</h4>
<p>This is more of a layout problem actually, but is quite an important one. Given the limited width of the blog sidebar area, it becomes evident that it is impossible to display more than a couple of tabs simultaneously, if we go with the regular horizontal placement. So the best option is to have them show in a sleek drop down, which can store all the feeds one could possibly want.</p>
<p><em>With those issues addressed, we can now move on to development.</em></p>
<h3>Step 1 &#8211; XHTML</h3>
<p>The first part of the tutorial consists of laying down the XHTML structure for the feed widget. The snippet below (extracted from <strong>demo.html</strong> in the download archive) is everything you need to show the widget on your page (apart from the CSS and jQuery files, covered in the later steps).</p>
<h4>demo.html</h4>
<pre class="brush:html">&lt;div id="feedWidget"&gt;

	&lt;div id="activeTab"&gt;
		&lt;!-- The name of the current tab is inserted here --&gt;
	&lt;/div&gt;

	&lt;div class="line"&gt;&lt;/div&gt;

	&lt;div id="tabContent"&gt;
		&lt;!-- The feed items are inserted here --&gt;
	&lt;/div&gt;

&lt;/div&gt;
</pre>
<p>As the widget is entirely dependent on JavaScript to function, there is little point in providing a fallback solution. The best we can do is to entirely hide it from view if JS is disabled. This is why the <strong>feedWidget</strong> div is hidden with <strong>display:non</strong>e in the stylesheet file, and shown with jQuery&#8217;s <strong>show()</strong> method in <strong>script.js</strong> (which will be run only if JS is available).</p>
<p>Now lets move to the next step.</p>
<div id="attachment_664" class="wp-caption alignnone" style="width: 630px"><a href="http://cdn.tutorialzine.com/wp-content/uploads/2010/02/i11.jpg"><img class="size-full wp-image-664" title="Feed Widget With jQuery, CSS3 &amp; YQL" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/02/i11.jpg" alt="Feed Widget With jQuery, CSS3 &amp; YQL" width="620" height="460" /></a><p class="wp-caption-text">Feed Widget With jQuery, CSS3 &amp; YQL</p></div>
<h3>Step 2 &#8211; CSS</h3>
<p>The styling of the widget is defined in <strong>styles.css</strong>. Only the styles that are directly used by the widget are included here. You can view the rest of the CSS declarations that define the looks of the page itself in that file.</p>
<h4>styles.css &#8211; Part 1</h4>
<pre class="brush:css">#feedWidget{
	background:url(img/bg.png) repeat-x #47525c;
	border:2px solid #48535e;
	margin:0 auto;
	width:200px;
	padding:5px;
	position:relative;

	/* Remains hidden if JS is not enabled: */
	display:none;
	z-index:20;
}

#activeTab.hover,.dropDownList{
	background:url(img/drop_arrow.png) no-repeat 95% 50% #47525c;
	border:1px solid #38434d;

	margin:-1px;

	cursor:pointer;

	/* CSS3 round corners: */
	-moz-border-radius:5px;
	-webkit-border-radius:5px;
	border-radius:5px;

}

#activeTab,.dropDownList div{
	color:white;
	cursor:pointer;
	font-size:20px;
	margin:0 2px 0 0;
	padding:5px;

	text-shadow:0 1px 1px black;
}

.line{
	height:1px;
	overflow:hidden;
	background-color:#2b353d;
	border-bottom:1px solid #687581;
	margin:10px 0;
}</pre>
<p>Notice that we define a special hover class for the <strong>#activeTab</strong> div, instead of the regular <strong>:hover</strong> pseudo-class. This is because the hover style should only be applied if there is more than one tab to be shown, which is impossible to determine with CSS alone. This is why we apply it with JS.</p>
<p>The <strong>dropDownList</strong> shares a number of properties with the <strong>hover</strong> class of the <strong>#activeTab</strong> div. The most effective way to write the CSS is to group those two together, and later individually apply only those rules that differ, as you can see in the snippet below:</p>
<h4>styles.css &#8211; Part 2</h4>
<pre class="brush:css">.dropDownList{
	background-image:none;
	position:absolute;

	border-top:none;
	padding:5px;

	/* We reset the roundness of the top corners, inherited by a previous rule: */

	-moz-border-radius-topleft: 0;
	-moz-border-radius-topright: 0;
	-webkit-border-top-left-radius: 0;
	-webkit-border-top-right-radius: 0;
	border-top-left-radius: 0;
	border-top-right-radius: 0;
}

.dropDownList div:hover{
	background-color:#505e6b;
}

#tabContent div{
	/* The feed entry divs */

	background-color:#EEEEEE;
	color:#555555;
	font-size:10px;
	margin-bottom:10px;
	padding:5px;
	position:relative;

	-moz-border-radius:5px;
	-webkit-border-radius:5px;
	border-radius:5px;

	/* CSS3 box shadow: */
	-moz-box-shadow:0 1px 1px black;
	-webkit-box-shadow:0 1px 1px black;
	box-shadow:0 1px 1px black;
}
</pre>
<p>We apply a number of CSS3 rules here: <strong>border-radius</strong> for pure CSS rounded corners and <strong>box-shadow</strong> for adding a drop shadow below the feed items. They are provided with the -<strong>moz</strong>- and -<strong>webkit</strong>- vendor prefixes, because the regular version is not yet supported in any browser (but we supply it as well for future-proofing).</p>
<div id="attachment_665" class="wp-caption alignnone" style="width: 630px"><a href="http://cdn.tutorialzine.com/wp-content/uploads/2010/02/i31.jpg"><img class="size-full wp-image-665" title="The Dropdown" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/02/i31.jpg" alt="The Dropdown" width="620" height="260" /></a><p class="wp-caption-text">The Dropdown</p></div>
<h3>Step 3 &#8211; jQuery</h3>
<p>After including the jQuery library into the page, it is now possible to leverage the methods it provides and build some complex interactions that would otherwise be impossible (or at least would take too much development resources).  The JavaScript code is located in <strong>scripts.js</strong> in the demo files.</p>
<h4>script.js &#8211; Part 1</h4>
<pre class="brush:js">/* Configuration: */

var tabs = {
	"@tutorialzine" : {
		"feed"		: "http://twitter.com/statuses/user_timeline/67315866.rss",
		"function"	: twitter
	},

	"Latest Tutorials": {
		"feed"		: "http://feeds.feedburner.com/Tutorialzine",
		"function"	: rss
	},

	"Smashing Mag": {
		"feed"		: "http://rss1.smashingmagazine.com/feed/",
		"function"	: rss
	},

	"Script &amp; Style" : {
		"feed"		: "http://feeds2.feedburner.com/ScriptAndStyle",
		"function"	: rss
	}
}

$(document).ready(function(){
	/* This code is executed after the DOM has been completely loaded */

	/* Counting the tabs: */
	var totalTabs=0;
	$.each(tabs,function(){totalTabs++;})

	$('#feedWidget').show().mouseleave(function(){

		/* If the cursor left the widet, hide the drop down list: */
		$('.dropDownList').remove();
		$('#activeTab').removeClass('hover');

	}).mouseenter(function(){

		if(totalTabs&gt;1) $('#activeTab').addClass('hover');

	});

	$('#activeTab').click(showDropDown);

	/* Using the live method to bind an event, because the .dropDownList does not exist yet: */

	$('.dropDownList div').live('click',function(){

 		/* Calling the showDropDown function, when the drop down is already shown, will hide it: */
		showDropDown();
		showTab($(this).text());
	});

	/* Showing one of the tabs on load: */

	showTab('@tutorialzine');
});
</pre>
<p>Notice the <strong>tabs</strong> object. It contains the declarations of the different feeds we want to use, along with a function that handles the output of those feeds to the page. The name of the property (before the colon) is inserted as a tab name, and when passed to the <strong>showTab()</strong> function, shows the contents of this feed inside the widget. This is how we load the &#8216;<strong>@tutorialzine</strong>&#8216; tweets on page load.</p>
<h4>script.js &#8211; Part 2</h4>
<pre class="brush:js">function showTab(key)
{
	var obj = tabs[key];
	if(!obj) return false;

	var stage = $('#tabContent');

	/* Forming the query: */
	var query = "select * from feed where url='"+obj.feed+"' LIMIT 5";

	/* Forming the URL to YQL: */
	var url = "http://query.yahooapis.com/v1/public/yql?q="+encodeURIComponent(query)+"&amp;format=json&amp;callback=?";

	$.getJSON(url,function(data){

		stage.empty();

		/* item exists in RSS and entry in ATOM feeds: */

		$.each(data.query.results.item || data.query.results.entry,function(){

			try{
				/* Trying to call the user provided function, "this" the rest of the feed data: */
				stage.append(obj['function'](this));

			}
			catch(e){
				/* Notifying users if there are any problems with their handler functions: */
				var f_name =obj['function'].toString().match(/function\s+(\w+)\(/i);
				if(f_name) f_name = f_name[1];

				stage.append('&lt;div&gt;There is a problem with your '+f_name+ ' function&lt;/div&gt;');
				return false;
			}
		})

	});

	$('#activeTab').text(key);
}

function showDropDown()
{
	if(totalTabs&lt;2) return false;

	if($('#feedWidget .dropDownList').length)
	{
	/* If the drop down is already shown, hide it: */

	$('.dropDownList').slideUp('fast',function(){ $(this).remove(); })

	return false;

	}

	var activeTab = $('#activeTab');

	var offsetTop = (activeTab.offset().top - $('#feedWidget').offset().top )+activeTab.outerHeight() - 5;

	/* Creating the drop down div on the fly: */

	var dropDown = $('&lt;div&gt;').addClass('dropDownList').css({

		'top'	: offsetTop,
		'width'	: activeTab.width()

	}).hide().appendTo('#feedWidget')

	$.each(tabs,function(j){

		/* Populating the div with the tabs that are not currently shown: */
		if(j==activeTab.text()) return true;

		$('&lt;div&gt;').text(j).appendTo(dropDown);
	})

	dropDown.slideDown('fast');

}
</pre>
<p>The <strong>showTab</strong> function takes a tab name as a parameter and displays it in the widget, after forming the corresponding <strong>YQL</strong> URL, and fetching it with the <strong>getJSON()</strong> method. After this, the response is looped with <strong>$.each</strong> and the function that was provided in the tab definition is called.</p>
<p>You can additionally switch the active tab from outside the widget code, by calling <strong>showTab()</strong> with a different tab name (and thus creating custom controls for the widget).</p>
<h4>script.js &#8211; Part 3</h4>
<pre class="brush:js">function twitter(item)
{
	/* Formats the tweets, by turning hashtags, mentions an URLS into proper hyperlinks: */

	return $('&lt;div&gt;').html(
		formatString(item.description || item.title)+
		' &lt;a href="'+(item.link || item.origLink)+'" target="_blank"&gt;[tweet]&lt;/a&gt;'
	);
}

function rss(item)
{
	return $('&lt;div&gt;').html(
		formatString(item.title.content || item.title)+
		' &lt;a href="'+(item.origLink || item.link[0].href || item.link)+'" target="_blank"&gt;[read]&lt;/a&gt;'
	);
}

function formatString(str)
{
	/* This function was taken from our Twitter Ticker tutorial - http://tutorialzine.com/2009/10/jquery-twitter-ticker/ */

	str = str.replace(/&lt;[^&gt;]+&gt;/ig,'');
	str=' '+str;
	str = str.replace(/((ftp|https?):\/\/([-\w\.]+)+(:\d+)?(\/([\w/_\.]*(\?\S+)?)?)?)/gm,'&lt;a href="$1" target="_blank"&gt;$1&lt;/a&gt;');
	str = str.replace(/([^\w])\@([\w\-]+)/gm,'$1@&lt;a href="http://twitter.com/$2" target="_blank"&gt;$2&lt;/a&gt;');
	str = str.replace(/([^\w])\#([\w\-]+)/gm,'$1&lt;a href="http://twitter.com/search?q=%23$2" target="_blank"&gt;#$2&lt;/a&gt;');
	return str;
}
</pre>
<p>In the last part of the code, we have the two functions &#8211; <strong>twitter</strong> and <strong>rss</strong>. These take an object passed from the <strong>$.each</strong> loop in <strong>showTab()</strong> and find their way to the link and title of the feed item, depending on whether it is RSS or ATOM.</p>
<p>You can create your own functions and include them in the <strong>tabs</strong> object. This way you can expand the functionality for feeds that are not limited to text. It is only important that you return the results as a <strong>&#8216;&lt;div&gt;&#8230;.&lt;/div&gt;&#8217;</strong> string.</p>
<p><strong>With this our Sleek Feed Widget is complete!</strong></p>
<h3>To Wrap It Up</h3>
<p>You are free to use and build upon the widget any way you see fit. The code is easy to modify and you can quickly implement all sorts of functionality.</p>
<p>If you liked this tutorial, be sure to <a href="http://twitter.com/Tutorialzine" target="_blank">follow us on twitter</a> for the latest and greatest web dev resources on the web.</p>
<p><strong>What do you think? How would you modify this code?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/02/feed-widget-jquery-css-yql/feed/</wfw:commentRss>
		<slash:comments>37</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using apc
Page Caching using apc
Object Caching 549/590 objects using apc
Content Delivery Network via cdn.tutorialzine.com

Served from: tutorialzine.com @ 2012-05-21 03:47:13 -->
