Nettuts+ » JavaScript & AJAX http://net.tutsplus.com Web Development & Design Tutorials Fri, 19 Mar 2010 22:35:57 +0000 http://wordpress.org/?v=2.9.2 en hourly 1 Quick Tip: How to Write a Neat FlipNav Script http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-how-to-write-a-neat-flipnav-script/ http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-how-to-write-a-neat-flipnav-script/#comments Fri, 19 Mar 2010 21:32:36 +0000 Jeffrey Way http://net.tutsplus.com/?p=10395 Somehow, I inadvertently started a navigation series over the last few weeks. It’s purely coincidence, mostly spawned by emails and such. This week, we’re going to mimic the neat navigation functionality, found on JohnMayer.com. Simply mouse over one of the navigation items to see the effect. However, we’re going to make it a bit more flexible by removing the need for images. We’ll achieve the effect using only CSS and JavaScript.

Other Viewing Options

]]>
http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-how-to-write-a-neat-flipnav-script/feed/ 27
Quick Tip: Cross Domain AJAX Request with YQL and jQuery http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-cross-domain-ajax-request-with-yql-and-jquery/ http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-cross-domain-ajax-request-with-yql-and-jquery/#comments Thu, 18 Mar 2010 01:27:41 +0000 Jeffrey Way http://net.tutsplus.com/?p=10225 For security reasons, we cannot make cross-domain AJAX requests with jQuery. For example, I can’t call the load() method, and pass in ‘cnn.com’. As we’d be loading in scripts and such, as well as our desired content, this would present a significant security risk. Nonetheless, there may be times when this is specifically what you require. Thanks to YQL, we can allow for this functionality rather easily!

The Script

// Accepts a url and a callback function to run.
function requestCrossDomain( site, callback ) {

	// If no url was passed, exit.
	if ( !site ) {
		alert('No site was passed.');
		return false;
	}

	// Take the provided url, and add it to a YQL query. Make sure you encode it!
	var yql = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from html where url="' + site + '"') + '&format=xml&callback=?';

	// Request that YSQL string, and run a callback function.
	// Pass a defined function to prevent cache-busting.
	$.getJSON( yql, cbFunc );

	function cbFunc(data) {
	// If we have something to work with...
	if ( data.results[0] ) {
		// Strip out all script tags, for security reasons.
		// BE VERY CAREFUL. This helps, but we should do more.
		data = data.results[0].replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');

		// If the user passed a callback, and it
		// is a function, call it, and send through the data var.
		if ( typeof callback === 'function') {
			callback(data);
		}
	}
	// Else, Maybe we requested a site that doesn't exist, and nothing returned.
	else throw new Error('Nothing returned from getJSON.');
	}
}

Call the Function

requestCrossDomain('http://www.cnn.com', function(results) {
   $('#container').html(results);
});

Stripping Out the Script Tags

I had to progress rather quickly in the video, so perhaps the regular expression that strips out the <script> tags require further detail.

.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');

When we load our desired page, it’s also going to load scripts! You must be very careful when making cross domain request. It definitely helps to strip out the <script> tags, but you should do more in an actual project.

Let’s take the regular expression step by step.

<script[^>]*>

Find all open script tags; however, they could come in many forms: <script type=”text/javascript” src=”bla.js”></script> , or <script type=”text/javascript”>lots of code here…</script> . For this reason, we add a character class ( [^>]* ), which mean, “Find zero or more of anything that IS NOT a closing bracket. This will take care of the attributes and values.

[\s\S]*?

Next, we want to strip out all code, as well as any spacing. \s refers to a space. \S refers to anything that IS NOT a space. Once again, we add a * after the character class to designate that we want zero or more occurrences.

<\/script>

Finally, find the closing script tags.


Further Reading

This is only meant to provide a glimpse of how we can achieve this functionality. Only so much can be covered in a five minute video. Feel free to discuss in the comments, and you’re always encouraged to fork the source code to improve upon it!

]]>
http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-cross-domain-ajax-request-with-yql-and-jquery/feed/ 34
Learning Server-Side JavaScript with Node.js http://net.tutsplus.com/tutorials/javascript-ajax/learning-serverside-javascript-with-node-js/ http://net.tutsplus.com/tutorials/javascript-ajax/learning-serverside-javascript-with-node-js/#comments Mon, 15 Mar 2010 16:06:48 +0000 Devon Govett http://net.tutsplus.com/?p=10044 Node.js is all the buzz at the moment, and makes creating high performance, real-time web applications easy. It allows JavaScript to be used end to end, both on the server and on the client. This tutorial will walk you through the installation of Node and your first “Hello World” program, to building a scalable streaming Twitter server.

What is Node.js?

JavaScript has traditionally only run in the web browser, but recently there has been considerable interest in bringing it to the server side as well, thanks to the CommonJS project. Other server-side JavaScript environments include Jaxer and Narwhal. However, Node.js is a bit different from these solutions, because it is event-based rather than thread based. Web servers like Apache that are used to serve PHP and other CGI scripts are thread based because they spawn a system thread for every incoming request. While this is fine for many applications, the thread based model does not scale well with many long-lived connections like you would need in order to serve real-time applications like Friendfeed or Google Wave.

“Every I/O operation in Node.js is asynchronous…”

Node.js, uses an event loop instead of threads, and is able to scale to millions of concurrent connections. It takes advantage of the fact that servers spend most of their time waiting for I/O operations, like reading a file from a hard drive, accessing an external web service or waiting for a file to finish being uploaded, because these operations are much slower than in memory operations. Every I/O operation in Node.js is asynchronous, meaning that the server can continue to process incoming requests while the I/O operation is taking place. JavaScript is extremely well suited to event-based programming because it has anonymous functions and closures which make defining inline callbacks a cinch, and JavaScript developers already know how to program in this way. This event-based model makes Node.js very fast, and makes scaling real-time applications very easy.


Step 1 Installation

Node.js runs on Unix based systems, such as Mac OS X, Linux, and FreeBSD. Unfortunately, Windows is not yet supported, so if you are a Windows user, you can install it on Ubuntu Linux using Virtualbox. To do so, follow this tutorial. You will need to use the terminal to install and run Node.js.

  1. Download the latest release of Node.js from nodejs.org (the latest version at the time of this writing is 0.1.31) and unzip it.
  2. Open the terminal, and run the following commands.
    cd /path/to/nodejs
    make
    sudo make install
    		

    A lot of messages will be outputted to the terminal as Node.js is compiled and installed.


Step 2 Hello World!

Every new technology starts with a “Hello World!” tutorial, so we will create a simple HTTP server that serves up that message. First, however, you have to understand the Node.js module system. In Node, functionality is encapsulated in modules which must be loaded in order to be used. There are many modules listed in the Node.js documentation. You load these modules by using the require function like so:

var sys = require("sys");

This loads the sys module, which contains functions for dealing with system level tasks like printing output to the terminal. To use a function in a module, you call it on the variable that you stored the module in, in our case sys.

sys.puts("Hello World!");

Running these two lines is as simple as running the node command with the filename of the javascript file as an argument.

node test.js

This will output “Hello World!” to the command line when run.

To create an HTTP server, you must require the http module.

var sys = require("sys"),
    http = require("http");

http.createServer(function(request, response) {
    response.sendHeader(200, {"Content-Type": "text/html"});
    response.write("Hello World!");
    response.close();
}).listen(8080);

sys.puts("Server running at http://localhost:8080/");

This script imports the sys and http modules, and creates an HTTP server. The anonymous function that is passed into http.createServer will be called whenever a request comes in to the server. Once the server is created, it is told to listen on port 8080. When a request to the server comes in, we first send HTTP headers with the content type and status code of 200 (successful). Then we send “Hello World!” and close the connection. You might notice that we have to explicitly close the connection. This will make it very easy to stream data to the client without closing the connection. If you run this script and go to http://localhost:8080/ in your browser, you will see “Hello World!”


Step 3 A Simple Static File Server

OK, so we have built an HTTP server, but it doesn’t send anything except for “Hello World,” no matter what URL you go to. Any HTTP server must be able to send static files such as HTML files, images and other files. The following code does just that:

var sys = require("sys"),
    http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs");

http.createServer(function(request, response) {
    var uri = url.parse(request.url).pathname;
    var filename = path.join(process.cwd(), uri);
    path.exists(filename, function(exists) {
    	if(!exists) {
    		response.sendHeader(404, {"Content-Type": "text/plain"});
    		response.write("404 Not Found\n");
    		response.close();
    		return;
    	}

    	fs.readFile(filename, "binary", function(err, file) {
    		if(err) {
    			response.sendHeader(500, {"Content-Type": "text/plain"});
    			response.write(err + "\n");
    			response.close();
    			return;
    		}

    		response.sendHeader(200);
    		response.write(file, "binary");
    		response.close();
    	});
    });
}).listen(8080);

sys.puts("Server running at http://localhost:8080/");

We start by requiring all of the modules that we will need in our code. This includes the sys, http, url, path, and fs or filesystem modules. Next we create an HTTP server like we did before. This time, we will use the url module to parse the incoming URL of the request and find the pathname of the file being accessed. We find the actual filename on the server’s hard drive by using path.join, which joins process.cwd(), or the current working directory, with the path to the file being requested. Next, we check if the file exists, which is an asynchronous operation and thus requires a callback. If the file does not exist, a 404 Not Found message is sent to the user and the function returns. Otherwise, we read the file using the fs module using the “binary” encoding, and send the file to the user. If there is an error reading the file, we present the error message to the user, and close the connection. Because all of this is asynchronous, the server is able to serve other requests while reading the file from the disk no matter how large it is.

If you run this example, and navigate to http://localhost:8080/path/to/file, that file will be shown in your browser.


Step 4 A Real Time Tweet Streamer

Building on our static file server, we will build a server in Node.js that streams tweets to a client that is served through our static file server. To start, we will need one extra module in this example: the events module. Node has a concept called an EventEmitter, which is used all over to handle event listeners for asynchronous tasks. Much like in jQuery or another client side JavaScript framework where you bind event listeners to things like mouse clicks, and AJAX requests, Node allows you to bind event listeners to many things, some of which we have already used. These include every I/O operation, such as reading a file, writing a file, checking if a file exists, waiting for HTTP requests, etc. The EventEmitter abstracts the logic of binding, unbinding, and triggering such event listeners. We will be using an EventEmitter to notify listeners when new tweets are loaded. The first few lines of our tweet streamer imports all of the required modules, and defines a function for handling static files, which was taken from our previous example.

var sys = require("sys"),
    http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs"),
    events = require("events");

function load_static_file(uri, response) {
	var filename = path.join(process.cwd(), uri);
	path.exists(filename, function(exists) {
		if(!exists) {
			response.sendHeader(404, {"Content-Type": "text/plain"});
			response.write("404 Not Found\n");
			response.close();
			return;
		}

		fs.readFile(filename, "binary", function(err, file) {
			if(err) {
				response.sendHeader(500, {"Content-Type": "text/plain"});
				response.write(err + "\n");
				response.close();
				return;
			}

			response.sendHeader(200);
			response.write(file, "binary");
			response.close();
		});
	});
}

We have used the http module to create a server before, but it is also possible to create an HTTP client using the module. We will be creating an HTTP client to load tweets from Twitter’s public timeline, which is performed by the get_tweets function.

var twitter_client = http.createClient(80, "api.twitter.com");

var tweet_emitter = new events.EventEmitter();

function get_tweets() {
	var request = twitter_client.request("GET", "/1/statuses/public_timeline.json", {"host": "api.twitter.com"});

	request.addListener("response", function(response) {
		var body = "";
		response.addListener("data", function(data) {
			body += data;
		});

		response.addListener("end", function() {
			var tweets = JSON.parse(body);
			if(tweets.length > 0) {
				tweet_emitter.emit("tweets", tweets);
			}
		});
	});

	request.close();
}

setInterval(get_tweets, 5000);

First, we create an HTTP client on port 80 to api.twitter.com, and create a new EventEmitter. The get_tweets function creates an HTTP “GET” request to Twitter’s public timeline, and adds an event listener that will be triggered when Twitter’s servers respond. Because Node.js is asynchronous, the data in the body of the response comes in chunks, which are picked up by the response’s “data” listener. This listener simply appends the chunk to the body variable. Once all of the chunks have come in, the “end” listener is triggered, and we parse the incoming JSON data. If more than one tweet is returned, we emit the “tweets” event on our tweet_emitter, and pass in the array of new tweets. This will trigger all of the event listeners listening for the “tweets” event, and send the new tweets to each client. We retreive the new tweets every five seconds, by using setInterval.

Finally, we need to create the HTTP server to handle requests.

http.createServer(function(request, response) {
    var uri = url.parse(request.url).pathname;
    if(uri === "/stream") {

    	var listener = tweet_emitter.addListener("tweets", function(tweets) {
    		response.sendHeader(200, { "Content-Type" : "text/plain" });
    		response.write(JSON.stringify(tweets));
    		response.close();

    		clearTimeout(timeout);
    	});

    	var timeout = setTimeout(function() {
    		response.sendHeader(200, { "Content-Type" : "text/plain" });
    		response.write(JSON.stringify([]));
    		response.close();

    		tweet_emitter.removeListener(listener);
    	}, 10000);

    }
    else {
    	load_static_file(uri, response);
    }
}).listen(8080);

sys.puts("Server running at http://localhost:8080/");

Just as we did with our static file server, we create an HTTP server that listens on port 8080. We parse the requested URL, and if the URL is equal to "/stream", we will handle it, otherwise we pass the request off to our static file server. Streaming consists of creating a listener to listen for new tweets on our tweet_emitter, which will be triggered by our get_tweets function. We also create a timer to kill requests tht last over 10 seconds by sending them an empty array. When new tweets come in, we send the tweets as JSON data, and clear the timer. You will see how this works better after seeing the client side code, which is below. Save it as test.html in the same directory as the server side JavaScript.

<!DOCTYPE html>
<html>
	<head>
		<title>Tweet Streamer</title>
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
	</head>
	<body>
		<ul id="tweets"></ul>
		<script type="text/javascript">
		var tweet_list = $("#tweets");

		function load_tweets() {
			$.getJSON("/stream", function(tweets) {
				$.each(tweets, function() {
					$("<li>").html(this.text).prependTo(tweet_list);
				});
				load_tweets();
			});
		}

		setTimeout(load_tweets, 1000);
		</script>
	</body>
</html>

Here, we have a simple HTML page that imports the jQuery library and defines an unordered list to put the tweets in. Our client side JavaScript caches the tweet list, and runs the load_tweets function after one second. This gives the browser enough time to finish loading the page before we start the AJAX request to the server. The load_tweets function is very simple: It uses jQuery’s getJSON function to load /stream. When a response comes in, we loop through all of the tweets and prepend them to the tweet list. Then, we call load_tweets again. This effectively creates a loop that loads new tweets, which times out after ten seconds because of the timeout on the server. Whenever there are new tweets, they are pushed to the client which maintains a continuous connection to the server. This technique is called long-polling.

If you run the server using node and go to http://localhost:8080/test.html, you will see the Twitter public timeline stream into your browser.


Next Steps

Node.js is a very exciting technology that makes it easy to create high performance real time applications. I hope you can see its benefit, and can use it in some of your own applications. Because of Node’s great module system, it is easy to use prewritten code in your application, and there are many third party modules available for just about everything – including database connection layers, templating engines, mail clients, and even entire frameworks connecting all of these things together. You can see a complete list of modules on the Node.js wiki, and more Node tutorials can be found on How To Node. I would also recommend that you watch a video from JSConf, in which Ryan Dahl, the creator of Node, describes the design philosophy behind Node. That is available here.

I hope you have enjoyed this tutorial. If you have any comments, you can leave one here or send me a message on Twitter. Happy noding!

]]>
http://net.tutsplus.com/tutorials/javascript-ajax/learning-serverside-javascript-with-node-js/feed/ 44
How to Build a Lava-Lamp Style Navigation Menu http://net.tutsplus.com/tutorials/html-css-techniques/how-to-build-a-lava-lamp-style-navigation-menu/ http://net.tutsplus.com/tutorials/html-css-techniques/how-to-build-a-lava-lamp-style-navigation-menu/#comments Sat, 13 Mar 2010 20:17:50 +0000 Jeffrey Way http://net.tutsplus.com/?p=10015 A couple weeks ago, I created a screencast that demonstrated how to build a three-level navigation menu. In a response email, one of our readers requested a tutorial on how to build a lava-lamp style menu. Luckily, it’s quite a simple task, especially when using a JavaScript library. We’ll build one from scratch today.

Screenshot

Prefer a Screencast?

Step 1 Create the Mark-up

Before we can create this neat functionality, we need a base from which to work from. In your favorite code editor, create an unordered list for your navigation, and import both jQuery and jQuery UI, via Google.

<!DOCTYPE html>

<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>SpasticNav  Plugin</title>
	<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" />
</head>
<body>

<div id="container">

	<ul id="nav">
		<li id="selected"><a href="#">Home</a></li>
		<li><a href="#">About</a></li>
		<li><a href="#">Blog</a></li>
		<li><a href="#">More About My Portfolio</a></li>
		<li><a href="#">Contact</a></li>
	</ul>

</div>

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

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

</body>
</html>

Note how we gave an id of “selected” to the home page. This is fairly standard in most websites; it allows use to target the current page, and style that particular list item accordingly.

Next, we must decide how to best implement the lava-lamp functionality. To allow for reusability, we’ll package this little script into a plugin, and call it like:

$('#nav').spasticNav();

Since we’ve decided to build a plugin, let’s go ahead and create a new file for that script, and reference it in our mark-up. We’ll call it jquery.spasticNav.js.

<script type="text/javascript" src="js/jquery.spasticNav.js"></script>	

<script type="text/javascript">
$('#nav').spasticNav();
</script>
</body>

Step 2 Beginning the Plugin

To reduce the number of global variables that we must create, as well as remove any possibilities of the $ symbol clashing with other JavaScript libraries, let’s wrap our plugin in a self-executing anonymous function.

(function($) {

})(jQuery);

Now, jQuery will be passed into our plugin, and will be represented via the $ symbol.

Next, it’s generally a best practice to give the users of the plugin as much flexibility as possible. As such, we’ll give them the option of passing in an object-literal when they call the plugin to override a handful of settings. As I see it, they should be able to:

  • Set the amount of overlap for our little blob. This refers to how much the blob will exceed the height of the navigation menu.
  • Set the speed
  • Set a reset, which causes the blob to move back to the current page item (assuming that the user never clicks on a link)
  • Set the color of the blob. This can be accomplished with CSS, but it’s a nice convenience, nonetheless.
  • Set the easing option.

Now, we’ll name our plugin, and make it equal to a function. $.fn is simply an alias for jquery.prototype.

$.fn.spasticNav = function(options) {

};

Knowing that we’ll be allowing these overrides, we must make sure that we accept an “options” parameter.

Step 3 Configuration Options

Now that we’ve named our plugin, the next step is to create the configuration options.

options = $.extend({
	overlap : 20,
	speed : 500,
	reset : 1500,
	color : '#0b2b61',
	easing : 'easeOutExpo'
}, options);

Above, we’re taking the options variable, setting some default properties and values, and then extending it with whatever (if anything) the user passes in when they call the plugin. That way, the options they pass will override our default settings. For example, if, when I call this plugin, I pass:

$('#nav').spasticNav({
   speed : 2000,
   easing : 'easeOutElastic'
});

Those two properties will override the default settings, while the remainder of the options will remain the same.

Step 4 Implementing the Functionality

Now, we’re ready to cycle through each element that was passed to this plugin, and implement the lava-lamp functionality. Remember, we can’t assume that the user is going to pass a single element to this plugin. They could, if they wanted, reference a class, which refers to multiple items that should receive this functionality. As such, we’ll call this.each to iterate over each item in the wrapped set.

return this.each(function() {

});

Within this function, we’ll create some variables. Not all of them will immediately have values, but since the JavaScript engine will hoist all variable names to the top of the function anyways (behind the scenes), it’s generally a best practice to declare them at the top, and then initialize them later.

var nav = $(this),
	currentPageItem = $('#selected', nav),
	blob,
	reset;
  • nav : “Caches” this, wrapped in the jQuery object.
  • currentPageItem : Contains the list item with an id of selected. We pass a second parameter to set the context to search from. That way, we don’t have to traverse the entire dom to find this element.
  • blob : For lack of a better word, this variable will reference the highlighter, that will follow our mouse when we hover over the menu.
  • reset : This will store a reference to the setTimeout function that will create later. It’s needed in order to call clearTimeout. More on this soon…

Now that we’ve declared/initialized our variables, let’s create the actual blob, so to speak.

$('<li id="blob"></li>').css({
	width : currentPageItem.outerWidth(),
	height : currentPageItem.outerHeight() + options.overlap,
	left : currentPageItem.position().left,
	top : currentPageItem.position().top - options.overlap / 2,
	backgroundColor : options.color
}).appendTo(this);

The reason why we’re calling the CSS method, rather than simply adding a class, is because these values will vary depending on the current page’s list item. As such, we must use JavaScript to retrieve they values.

  • width: Get the width of currentPageItem, including any borders and padding.
  • height: Get the height of currentPageItem, including any borders and padding. Also, add the amount of overlap, to make the blob extend outside of the menu.
  • left: Sets the left property of the blob equal to the left position of the currentPageItem. (We must set a positioning context in our CSS for this value to take effect.)
  • top: Sets the top value as well, and vertically centers the blob.
  • backgroundColor: Sets the background color.

Finally, we append this new list item to this, or #nav.

Next, we need to store a reference to #blob. That way, we don’t have to search the DOM everytime we wish to access it. We declared the blob variable at the top of the function. Now, let’s initialize it.

blob = $('#blob', nav);

Step 5 The Hover Event

We must now “listen” for when the user hovers over one of the list items (excluding the blob of course) in our navigation menu. When they do, we’ll set the width and left properties of the blob equal to that of the currently hovered list item.

$('li:not(#blob)', nav).hover(function() {
	// mouse over
	clearTimeout(reset);
	blob.animate(
		{
			left : $(this).position().left,
			width : $(this).width()
		},
		{
			duration : options.speed,
			easing : options.easing,
			queue : false
		}
	);
}, function() {
	// mouse out
	reset = setTimeout(function() {
		blob.animate({
			width : currentPageItem.outerWidth(),
			left : currentPageItem.position().left
		}, options.speed)
	}, options.reset);

});

To summarize the script above…

  • Get all list items – not the #blob – within the navigation menu, and when they’re hovered over, run a function.
  • Animate the blob, and set its left and width values equal to that of the hovered list item.
  • Pass an object literal as the second parameter of animate, and set the duration and easing equal to what we set in our configuration options. Set queue to false to prevent animation build-up.
  • When they mouse out, call setTimeOut, which will push the blob back to the current page item. If we didn’t do this, and the user didn’t click on a navigation link, the menu would show that they were on
    a different page entirely. This will, after a second or so, animate the blob back to currentPageItem.

And that’s all there is to it! This is a super simple plugin. The next step is to style our navigation menu.

Step 6 Styling the Menu

Without any styling, our menu should look similar to this:

Unstyled mark-up

Let’s first style the “nav” ul. Open your style.css file, and add:

#nav {
	position: relative;
	background: #292929;
	float: left;
}
Styling the navigation menu

Next, we’ll style each list item.

#nav li {
	float: left;
	list-style: none;
	border-right: 1px solid #4a4a4a;
	border-left: 1px solid black;
}

This simply floats each list item to the left, and adds a border to each side.

Styling the list items

Moving along, we next must style the anchor tags within our navigation menu.

#nav li a {
	color: #e3e3e3;
	position: relative;
	z-index: 2;
	float: left;
	font-size: 30px;
	font-family: helvetica, arial, sans-serif;
	text-decoration: none;
	padding: 30px 45px;
}

We’re setting a color, floating them to the left, setting some font values, and a healthy amount of padding. Take note of the z-index property. This is a necessity, and will be explained shortly. However, remember that, in order to adjust the z-index, we must set a positioning context, which we’ve done.

Styling the anchor tags

Because we’re not implementing a full reset stylesheet, let’s ensure that we zero out any default margins and padding on our ul and li, just to save any potential headaches.

ul, li {
	margin: 0; padding: 0;
}

The last step is to style the blob itself!

#blob {
	border-right: 1px solid #0059ec;
	border-left: 1px solid #0059ec;
	position: absolute;
	top: 0;
	z-index : 1;
	background: #0b2b61;
	background: -moz-linear-gradient(top, #0b2b61, #1153c0);
	background: -webkit-gradient(linear, left top, left bottom, from(#0b2b61), to(#1153c0));
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
	-moz-box-shadow: 2px 3px 10px #011331;
	-webkit-box-shadow: 2px 3px 10px #011331;
}

Once again, we set some pretty colors for our borders, and add some background colors (including CSS3 gradients/borders/shadows for Firefox and Safari/Chrome). Once again, we see that z-index property. Without this, the blob will display above all of the text in the navigation menu. To counter this, we must be sure that its z-index property is LOWER than the list item’s! We also must set the position to absolute in order to adjust its top and left values with our plugin.

Screenshot

Conclusion

That’s all there is to it! With minimal effort, we’ve created a really neat looking navigation menu from scratch. Let me know if you have any questions! Thanks for reading and watching.

]]>
http://net.tutsplus.com/tutorials/html-css-techniques/how-to-build-a-lava-lamp-style-navigation-menu/feed/ 102
Quick Tip: The Difference Between Live() and Delegate() http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-the-difference-between-live-and-delegate/ http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-the-difference-between-live-and-delegate/#comments Wed, 10 Mar 2010 18:03:18 +0000 Jeffrey Way http://net.tutsplus.com/?p=9841 In jQuery 1.3, the team introduced the live() method, which allows us to bind event handlers to elements on the page, as well as any that might be created in the future dynamically. Though not perfect, it definitely proved to be helpful. Most notably, live() bubbles all the way up, and attaches the handler to the document. It also ceases to work well when chaining method calls, unfortunately. Delegate() was introduced in version 1.4, which almost does the same thing, but more efficiently.

We’ll examine the specific differences between the two methods in today’s video quick tip. Thanks to the FireQuery Firebug extension, we’ll have the tools to more easily understand how each method functions.

Alternate Viewing Options

<ul id="items">
	<li> Click Me </li>
</ul>
// Bind attaches an event handler only to the elements
// that match a particular selector. This, expectedly,
// excludes any dynamically generated elements.
$("#items li").click(function() {
	$(this).parent().append("<li>New Element</li>");
});

// Live(), introduced in 1.3, allows for the binding
// of event handlers to all elements that match a
// selector, including those created in the future.
// It does this by attaching the handler to the document.
// Unfortunately, it does not work well with chaining.
// Don't expect to chain live() after calls like
// children().next()...etc.
$("li").live("click", function() {
	$(this).parent().append("<li>New Element</li>");
});	

// Delegate, new to version 1.4, perhaps should have been a complete
// replacement for Live(). However, that obviously
// would have broken a lot of code! Nonetheless,
// delegate remedies many of the short-comings
// found in live(). It attaches the event handler
// directly to the context, rather than the document.
// It also doesn't suffer from the chaining issues
// that live does. There are many performance benefits
// to using this method over live().
$('#items').delegate('li', 'click', function() {
	$(this).parent().append('<li>New Element</li>');
});	

// By passing a DOM element as the context of our selector, we can make
// Live() behave (almost) the same way that delegate()
// does. It attaches the handler to the context, not
// the document - which is the default context.
// The code below is equivalent to the delegate() version
// shown above.
$("li", $("#items")[0]).live("click", function() {
	$(this).parent().append("<li>New Element</li>");
});

Conclusion

This can definitely be a confusing topic. Please feel free to ask questions, or discuss within the comments. Thanks so much to Elijah Manor for clarifying a few things for me on this topic!

]]>
http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-the-difference-between-live-and-delegate/feed/ 31
Uncovering jQuery’s Hidden Features http://net.tutsplus.com/tutorials/javascript-ajax/uncovering-jquerys-hidden-features/ http://net.tutsplus.com/tutorials/javascript-ajax/uncovering-jquerys-hidden-features/#comments Mon, 08 Mar 2010 16:15:53 +0000 James Padolsey http://net.tutsplus.com/?p=9472 jQuery is not always as it appears. There's a lot of cool stuff going on under the surface, and there are many methods just waiting to be discovered, and many potential usages of jQuery's API that you may not have considered before. In this article I'll be taking you through a few of the not-so-obvious things I've discovered about jQuery.

1. Understand jQuery!

When you call 'jQuery' what happens?

The jQuery function itself is very simple:

jQuery = function (selector, context) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init(selector, context);
};

Under its skin, the jQuery function (commonly referred to as the "wrapper" function) simply returns an instantiated jQuery object — i.e. an instance of the 'jQuery.fn.init' constructor.

This is useful to know; with this information we know that each time we call 'jQuery' we're actually creating a totally unique object with a set of properties. jQuery is clever in that it gives you an object that can be treated as an array. Each of your elements (all together, commonly known as the "collection") is referenced within the object under a numerical index, just like within an array. And jQuery also gives this object a 'length' property, just as you would expect from an array. This opens up a world of possibilities. For one, it means that we can borrow some functionality from 'Array.prototype'. jQuery's 'slice' method is a good example of this — modified from the source:

/* ... jQuery.fn.extend({ ... */
slice: function() {
    return this.pushStack(
        Array.prototype.slice.apply( this, arguments ),
        "slice",
        Array.prototype.slice.call(arguments).join(",")
    );
},
/* ... */

The native 'slice' method doesn't care that 'this' is not a real array– it'll be fine with anything that's got a 'length' property and [0], [1], [2] etc.

There are some other interesting properties within this jQuery object — '.selector' and '.context' will, most of the time, reflect the arguments that you pass into 'jQuery(…)'.

var jqObject = jQuery('a');
jqObject.selector; // => "a"

One thing that's important to note is that jQuery will sometimes give you new jQuery objects to work with. If you run a method that changes the collection in some way, such as '.parents()', then jQuery won't modify the current object; it'll simply pass you a brand new one:

var originalObject = jQuery('a');
var anotherObject = originalObject.parents();

originalObject === anotherObject; // => false

All methods that appear to mutate the collection in some way return a brand new jQuery object — you can still access the old object though, via '.end()', or more verbosely, via '.prevObject'.

2. Bread-and-butter Element Creation

Central to jQuery's DOM capabilities, is its element creation syntax. 1.4 brought with it an entirely new way to create your elements quickly and succinctly. E.g.

var myDiv = jQuery('<div/>', {
    id: 'my-new-element',
    class: 'foo',
    css: {
        color: 'red',
        backgrondColor: '#FFF',
        border: '1px solid #CCC'
    },
    click: function() {
        alert('Clicked!');
    },
    html: jQuery('<a/>', {
        href: '#',
        click: function() {
            // do something
            return false;
        }
    })
});

As of 1.4 you can pass a second argument to the jQuery function when you're creating an element — the object you pass will, for the most part, act as if you were passing it to '.attr(…)'. However, jQuery will map some of the properties to its own methods, for example, the 'click' property maps to jQuery's 'click' method (which binds an event handler for the 'click' event) and 'css' maps to jQuery's 'css' method etc.

To check out what properties map to jQuery's methods, open your console and type 'jQuery.attrFn'.

3. Serialize your Inputs

jQuery provides a method that you can use to serialize all of the inputs within one or more forms. This is useful when submitting data via XHR ("Ajax"). It's been in jQuery for a long time but it's not often talked about and so many developers don't realise it's there. Submitting an entire form via Ajax, using jQuery, couldn't be simpler:

var myForm = $('#my-form');
jQuery.post('submit.php', myForm.serialize(), function(){
    alert('Data has been sent!');
});

jQuery also provides the 'serializeArray' method, which is designed to be used with multiple forms, and the 'param' helper function (under the jQuery namespace) which takes a regular object and returns a query string, e.g.

var data = {
    name: 'Joe',
    age: 44,
    profession: 'Web Developer'
};

jQuery.param(data); // => "name=Joe&age=44&profession=Web+Developer"

4. Animate Anything

jQuery's 'animate' method is probably the most flexible of jQuery's methods. It can be used to animate pretty much anything, not just CSS properties, and not just DOM elements. This is how you would normally use 'animate':

jQuery('#box').animate({
    left: 300,
    top: 300
});

When you specify a property to animate (e.g. 'top') jQuery checks to see if you're animating something with a style property ('element.style'), and it checks if the specified property ('top') is defined under 'style' — if it's not then jQuery simply updates 'top' on the element itself. Here's an example:

jQuery('#box').animate({
    top: 123,
    foo: 456
});

'top' is a valid CSS property, so jQuery will update 'element.style.top', but 'foo' is not a valid CSS property, so jQuery will simply update 'element.foo'.

We can use this to our advantage. Let's say, for example, that you want to animate a square on a canvas. First let's define a simple constructor and a 'draw' method that'll be called on every step of the animation:

function Square(cnvs, width, height, color) {

    this.x = 0;
    this.y = 0;
    this.width = width;
    this.height = height;
    this.color = color;

    this.cHeight = cnvs.height;
    this.cWidth = cnvs.width;
    this.cntxt = cnvs.getContext('2d');

}

Square.prototype.draw = function() {

    this.cntxt.clearRect(0, 0, this.cWidth, this.cHeight);
    this.cntxt.fillStyle = this.color;
    this.cntxt.fillRect(this.x, this.y, this.width, this.height);

};

We've created our 'Square' constructor, and one of its methods. Creating a canvas and then animating it couldn't be simpler:

// Create a <canvas/> element
var canvas = $('<canvas/>').appendTo('body')[0];
canvas.height = 400;
canvas.width = 600;

// Instantiate Square
var square = new Square(canvas, 70, 70, 'rgb(255,0,0)');

jQuery(square).animate({
    x: 300,
    y: 200
}, {
    // 'draw' should be called on every step
    // of the animation:
    step: jQuery.proxy(square, 'draw'),
    duration: 1000
});

This is a very simple effect, but it does clearly demonstrate the possibilities. You can see it in action here: http://jsbin.com/ocida (this will only work in browsers that support the HTML5 canvas)

5. jQuery.ajax Returns the XHR Object

jQuery's Ajax utility functions ('jQuery.ajax', 'jQuery.get', 'jQuery.post') all return an 'XMLHttpRequest' object which you can use to perform subsequent operations on any request. For example:

var curRequest;

jQuery('button.makeRequest').click(function(){
    curRequest = jQuery.get('foo.php', function(response){
        alert('Data: ' + response.responseText);
    });
});

jQuery('button.cancelRequest').click(function(){
    if (curRequest) {
        curRequest.abort(); // abort() is a method of XMLHttpRequest
    }
});

Here we're making a request whenever the 'makeRequest' button is clicked — and we're cancelling the active request if the user clicks the 'cancelRequest' button.

Another potential usage is for synchronous requests:

var myRequest = jQuery.ajax({
    url: 'foo.txt',
    async: false
});

console.log(myRequest.responseText);

Read more about the 'XMLHttpRequest' object and also be sure to check out jQuery's Ajax utilities.

6. Custom Queues

jQuery has a built-in queuing mechanism that's used by all of its animation methods (all of which use 'animate()' really). This queuing can be illustrated easily with a simple animation:

jQuery('a').hover(function(){
    jQuery(this).animate({paddingLeft:'+=15px'});
}, function(){
    jQuery(this).animate({paddingLeft:'-=15px'});
});

Quickly hovering over a bunch of anchors and then hovering over them again will cause the animations to queue up and occur one at a time — I'm sure many of you have witnessed this queuing effect before. If not, check it out here: http://jsbin.com/aqaku

The 'queue' method is similar to the well-known 'each' method in how it's called. You pass a function, which will eventually be called for each of the elements in the collection:

jQuery('a').queue(function(){
    jQuery(this).addClass('all-done').dequeue();
});

Passing just a function to 'queue' will cause that function to be added to the default 'fx' queue, i.e. the queue used by all animations done by jQuery. Therefore, this function will not be called until all current animations occurring on each element in the collection (in this case, all anchors) have completed.

Notice that we're adding a class of 'all-done' in the function above. As outlined, this class will only be added when all current animations are complete. We're also calling the 'dequeue' method. This is very important, as it will allow jQuery to continue with the queue (i.e. it lets jQuery know that you're finished with whatever you're doing). jQuery 1.4 provides another way of continuing the queue; instead of calling 'dequeue', simply call the first argument passed to your function:

jQuery('a').queue(function(nextItemInQueue){
    // Continue queue:
    nextItemInQueue();
});

This does exactly the same, although it's slightly more useful in that it can be called anywhere within your function, even within a mess of closures (that typically destroy the 'this' keyword). Of course, pre-jQuery-1.4 you could just save a reference to 'this', but that would get a bit tiresome.

To add a function to a custom queue, simply pass your custom queue's name as the first argument and the function as the second:

jQuery('a').queue('customQueueName', function(){
    // Do stuff
    jQuery(this).dequeue('customQueueName');
});

Notice that, since we're not using the default 'fx' queue, we also have to pass our queue's name to the 'dequeue' method, in order to allow jQuery to continue with our custom queue.

Read more about 'queue', 'dequeue' and 'jQuery.queue'.

7. Event Namespacing

jQuery provides a way for you to namespace events, which can be very useful when authoring plugins and third-party components. If needed, the user of your plugin can effectively disable your plugin by unbinding all event handlers that it's registered.

To add a namespace when registering an event handler, simply suffix the event name with a period and then your unique namespace (e.g. '.fooPlugin'):

jQuery.fn.foo = function() {

    this.bind('click.fooPlugin', function() {
        // do stuff
    });

    this.bind('mouseover.fooPlugin', function() {
        // do stuff
    });

    return this;
};

// Use the plugin:
jQuery('a').foo();

// Destroy its event handlers:
jQuery('a').unbind('.fooPlugin');

Passing just the namespace to 'unbind' will unbind all event handlers with that namespace.

Conclusion

So which ones did I miss? Any helpful features that you feel jQuery doesn’t document well enough? Let’s discuss in the comments!

]]>
http://net.tutsplus.com/tutorials/javascript-ajax/uncovering-jquerys-hidden-features/feed/ 47
How to Create a Simple iTunes-like Slider http://net.tutsplus.com/tutorials/html-css-techniques/how-to-create-a-simple-itunes-like-slider/ http://net.tutsplus.com/tutorials/html-css-techniques/how-to-create-a-simple-itunes-like-slider/#comments Fri, 05 Mar 2010 17:40:37 +0000 Siddharth http://net.tutsplus.com/?p=9563 When space is at a premium, making use of sliders is the optimal way to present information. Today, we’ll take a look at how to create a slider similar to the one used in the iTunes store.

iTunes Version

Developers often seek the functionality provided by sliders in order to fit lots of information in the space provided. But creating such a slider is not as difficult as you might think. With a little planning and some experimenting, you can create one rather quickly.

I believe a demo is worth a thousand words. Hit the demo and try it out yourselves.

Interested? Let’s get started right away!

Design Goals

Before we start coding, here are a few goals for this widget.

  • Minimize the space taken up by images by making the slideshow’s dimensions the same size of a single image and then fading between them.
  • Provide a vertical carousel of images on the side showing upcoming images.
  • Provide a method to manually move the carousel and the slideshow forward. In this instance, we make use of a simple anchor element.
  • On the carousel, the top most image is the next in line and will be displayed when the next button is clicked.
  • Minimize DOM manipulation as much as possible. That’s not to say we aren’t going to touch the DOM, it’s just that we aren’t going to meddle with the DOM too much.

Plan of Action

There are actually a handful of techniques to make a widget like this. For our purposes today, I’m going to stick with a technique which adheres to a saying:

When in doubt, use brute force.

Step 1: Setup the CSS for the gallery container so that all the main images collapse into taking the space of a single image. I’ll explain this point later below.

Step 2: Setup the CSS for the thumbnail container so that only three images are visible at once.

Step 3: Cycle through the images and assign a class to each thumbnail and image with a numeric index to identify each independently. For example, each image gets a class of thumb-xx where xx is a number.

Step 4: When the next button is clicked, move the carousel one thumbnail up and then display the thumbnail’s corresponding image.

These are the basic steps involved in creating such an effect. I’ll explain each step in detail as we go along.

Step 1: Core Markup

The HTML markup for the demo page looks like so:

<!DOCTYPE html>
<html lang="en-GB">
	<head>
		<title>iTunes slider</title>
		<link rel="stylesheet" href="style.css" type="text/css" />
	</head>

	<body>
    	<div id="container">
        	<h1>Create a simple iTunes-esque slider with jQuery</h1>
		<div>by Siddharth for the lovely folks at Net Tuts</div>
		<p>A simple slider/slideshow which mostly emulates the one on iTunes barring a few changes. Click the down button to cycle the images.</p> 

		<div id="gallery">
    		   <img src="img/1.jpg" />
    		   <img src="img/2.jpg" />
    		   <img src="img/3.jpg" />
    		   <img src="img/4.jpg" />
            	   <img src="img/5.jpg" />
            	   <img src="img/6.jpg" />
	        </div>

                <div id="thumbs">
    	   	   <img src="img/11.jpg" />
    		   <img src="img/22.jpg" />
    		   <img src="img/33.jpg" />
    		   <img src="img/44.jpg" />
            	   <img src="img/55.jpg" />
            	   <img src="img/66.jpg" />
	        </div>

        	<a href="#" id="next"></a>
        </div>

	<script type="text/javascript" src="js/jquery.js"></script>
	<script type="text/javascript" src="js/mocha.js"></script>

	</body>
</html>

Disregarding the boiler plate code, we have two container elements full of images: one for the main gallery images and one for the thumbnails. I’ve given an ID to both of them so they can be easily accessed from the JavaScript. We also include an anchor element which acts as the next button.

We include the jQuery library and our own script file at the end.

At the end of this stage, our demo page looks like just a list of images.

Tutorial Image

Step 2: CSS Styling

*{
	margin: 0;
	padding: 0;
	border: 0 none;
	outline: 0;
}

body{
	font-family: "Lucida Grande", "Verdana", sans-serif;
	font-size: 12px;
}

p{
	margin: 20px 0 40px 0;
}

h1{
	font-size: 30px;
	font-family: "Myriad Pro", "Lucida Grande", "Verdana", sans-serif;
	padding: 0;
	margin: 0;
}

h2{
	font-size: 20px;
}

#container{
	width: 900px;
	margin-left: auto;
	margin-right: auto;
	padding: 50px 0 0 0;
	position: relative;
}

img{
	display: block;
}

#gallery, #thumbs{
	float: left;
}

#gallery{
	width: 800px;
	height: 300px;
	overflow: hidden;
}

#gallery img{
	position: absolute;
}

#thumbs{
	width: 100px;
	height: 300px;
	overflow: hidden;
}

#next{
	display: block;
	width: 47px;
	height: 43px;
	background: url(img/arrow.png);
	position: relative;
	top: 257px;
	left: 855px;
}

#next:hover{
	background: url(img/arrowmo.png);
}

.clear{
	clear: both;
}

The CSS is pretty self explanatory but there are a couple of points I want you to take note of:

First up, notice that I’ve applied position: absolute to #gallery img. This makes sure that the images are stacked on top of each other instead of one below the other. This way we can later manipulate their opacity to decide which image to show.

Secondly, notice that the thumbs element has its height set to 300px. This is because the thumbnails in the demo are 100px tall each and I want the carousel to show 3 images at once. Essentially, for your own implementation, multiply the height of a thumbnail by the number of thumbnails you want to show at once to find the required height of the element.

Also, take note of the fact that we’ve set its overflow property to hidden to make sure no more than 3 thumbnails are shown at once.

After we’ve styled our slider, it looks like the image below. Notice that almost everything is in place. The last image is stacked at the top and is thus visible.

Tutorial Image

Step 3: JavaScript Implementation

Now that we have a solid framework and some basic styling in place, we can begin coding the required functionality. Note that we make extensive use of jQuery. Feel free to link to Google’s CDN if necessary.

Procuring the Elements and Prepping them

We first need to acquire the images and their corresponding thumbnails so that we can process them.

	var images = $("#gallery img");
	var thumbs = $("#thumbs img");
        var index = 0;

The above snippet will take care of obtaining the list of images and thumbnails, and storing them for later use. We also create a variable called index to denote which element to start from. For now, I’m setting it to start from the first element. Note that index is zero based.

	for (i=0; i<thumbs.length; i++)
	{
		$(thumbs[i]).addClass("thumb-"+i);
		$(images[i]).addClass("image-"+i);
	}

Next, we just iterate through both the lists and and add a class of thumb-xx or image-xx to each element where xx is a number. This lets us look for each individual thumbnail or image independently.

Hooking up the Handler

We now need to create an event handler and attach it to the next button so that we can do something when the button is clicked.

$("#next").click(sift);

The one liner above will take care of that. Essentially, we ask it to call the sift function everytime next is clicked.

function sift()
	{
		if (index<(thumbs.length-1)) {index+=1 ; }
		else {index=0}
		show (index);
	}

This is a very simple event handler actually. We just check to see what element is currently selected. If it is the last, we reset the index so the carousel goes back to the first element, thus creating a pseudo infinite carousel. Otherwise, we increment index by 1.

Next, we call the function show, passing in the index variable as a parameter. We’ll create the function in a bit.

Step 4: Implementing the Core Logic

function show(num)
	{
		images.fadeOut(400);
		$(".image-"+num).stop().fadeIn(400);
		var scrollPos = (num+1)*imgHeight;
		$("#thumbs").stop().animate({scrollTop: scrollPos}, 400);
	}

The show function implements the core functionality of this widget. Let me explain each part.

First, we fade out every image the gallery element contains. Next, we fade in just the required image making use of its class. Since each image can be accessed through its class and we have access to the positional index of the image, we just use the following selector: “.image-”+num

Next, we need to scroll the thumbnail element so that the required image is at the top of the carousel. There are two ways to go on about doing this.

The first method makes use of jQuery’s position property. This lets us find the element’s position relative to its parent element. Unfortunately, I’ve been running into quite a few problems with it and Chrome which means we’ll have to use our second method.

The next method is actually just as simple. Since we can easily obtain the height of a thumbnail and since each thumbnail is required to be of the same height, we can easily just find the product of the nth element’s position in the list and the height of a thumbnail to obtain its offset from the top.

var imgHeight = thumbs.attr("height");

The above line lets us obtain a thumbnail’s height. Remember that a collection of elements can be queried just like a normal element.

var scrollPos = (num+1)*imgHeight;

We now calculate the offset of the thumbnail we need. Since we need the thumbnail of the next element in the list and not of that image itself, we increment it by 1 before multiplying it by the height.

With all this info, we can now scroll the element to the height we need.

$("#thumbs").stop().animate({scrollTop: scrollPos}, 400);

We use jQuery’s animate property to alter the scrollTop property to the value we calculated above. If you are new to jQuery’s animation functions, refer to my earlier article. Essentially, we scroll the element x pixels from the top to create a carousel effect.

Step 5: A Few Tweaks

Polishing the Pseudo Infinite Effect

We are essentially done but a few quick bits of code will make it a little bit more polished.

thumbs.slice(0,3).clone().appendTo("#thumbs");

This line essentially takes the first three thumbnails, copies them over to the end of the list. The slice method selects the first three elements, the clone methods clones these DOM elements and finally the appendTo methods adds them to the passed element.

We can’t just use the appendTo method since it plucks the selected elements from their current position before placing it as required. We need the clone method to copy them first.

We do this to make sure when we approach the final few thumbnails, the illusion of an infinite carousel remains. Else, the user just sees empty blocks which isn’t really what we need.

Making it Auto Rotate

Making the widget auto rotate is actually very simple. Since we have a proper event handler in place, we just have to call the handler every n microseconds. The following line will take care of that:

setInterval(sift, 8000);

In the above code, I’ve asked to call the sift function every eight seconds. Remember, the duration is passed in as microseconds so n thousand equals n seconds.

Initializing the Widget

Currently, the page loads with the widget uninitialized. We’ll need to rectify this. All we need to do is to call the show function passing in the starting position as a parameter.

After you’ve attached the event handler, add this:

show(index);

The Final Code

And we are done! The final code looks like so:

$(document).ready(function()
{
	var index = 0;
	var images = $("#gallery img");
	var thumbs = $("#thumbs img");
	var imgHeight = thumbs.attr("height");
	thumbs.slice(0,3).clone().appendTo("#thumbs");
	for (i=0; i<thumbs.length; i++)
	{
		$(thumbs[i]).addClass("thumb-"+i);
		$(images[i]).addClass("image-"+i);
	}

	$("#next").click(sift);
	show(index);
	setInterval(sift, 8000);

	function sift()
	{
		if (index<(thumbs.length-1)){index+=1 ; }
		else {index=0}
		show (index);
	}

	function show(num)
	{
		images.fadeOut(400);
		$(".image-"+num).stop().fadeIn(400);
		var scrollPos = (num+1)*imgHeight;
		$("#thumbs").stop().animate({scrollTop: scrollPos}, 400);
	}
});

Conclusion

And there you have it: we’ve created a simple but useful slider. Hopefully you’ve found this tutorial interesting and useful. Feel free to reuse this code elsewhere in your projects, and chime in within the comments if you are running into difficulties.

Questions? Nice things to say? Criticisms? Hit the comments section and leave me a comment. Happy coding!

]]>
http://net.tutsplus.com/tutorials/html-css-techniques/how-to-create-a-simple-itunes-like-slider/feed/ 63
12 Steps to MooTools Mastery http://net.tutsplus.com/tutorials/javascript-ajax/12-steps-to-mootools-mastery/ http://net.tutsplus.com/tutorials/javascript-ajax/12-steps-to-mootools-mastery/#comments Thu, 04 Mar 2010 16:35:10 +0000 Jacob Thornton http://net.tutsplus.com/?p=9595 ]]> This tutorial is about understanding and mastering the MooTools library. It does so by offering a high level introduction to the history and foundations of the Core library: where to start, where to explore, what to master, and more.


1. Prototypal Inheritance

step 1

The foundation of the MooTools framework is really in the prototypal inheritance model of JavaScript. In classical languages, like C++ or Java, a class represents something like a data type or what Jeff Mott called a “blueprint.” These blueprints are then used in the creation of objects. In fact, in these languages nothing is actually created until the “new” operator explicitly invokes them.

With JavaScript however, everything is created immediately, even before you instantiate the objects with the “new” operator. As a prototypal language, this effectively means no blueprints, no “classes”. Instead, we go about using some objects as fully operational bases for other objects. As Douglas Crawford said, in precisely this way JavaScript becomes “more capable and offers more expressive power.” Let’s take a look:

function Nerd(iq) {
    this.iq = iq;
    this.glasses = true;
    this.pants = 'high';
}

function SuperPowers() {
    this.strongerThanLocomotive = true;
    this.fasterThanBullet = true;
    this.canLeapBuildings = true;
}

Nerd.prototype = new SuperPowers();

Nerd.prototype.willWinGirl = function (hotness) {
    if(this.iq > (hotness * 20) || this.strongerThanLocomotive){
        console.log('maybe');
    }
    else {
        console.log('nope');
    }
}

new Nerd(140).willWinGirl(10); // logs "maybe"

The example above is actually a rather popular means of introducing the concept of prototyping. However, if you’re finding this a little too abstract, perhaps a better way to approach this would be to look at prototyping a native JavaScript constructor like String, Array, etc. For example:

Array.prototype.eachhhh = function (fn) {
    for (var i = 0, l = this.length; i < l; i++) fn(this[i]);
}

[0,1,2,3].eachhhh(function(item){
    console.log(item); // logs: 0,1,2,3
});

Prototyping simple code patterns like the for loop above can save tons of time when working on larger projects. When using the MooTools framework, it's important to begin thinking of every constructor as being extendable; this is going to save you time down the line and make your code much more flexible. Furthermore, it's precisely this method of inheritance that is at the core of MooTools, and harnessing this frameworks power means making use of prototyping. Of course, what MooTools does is make this process a whole lot easier for you to access and take advantage of, but we will get into exactly how it does this later on in the article.


2. Object Literal Notation

step 2

Wayyyy back in 2006, Chris Heilman was already getting fanatical about the object literal syntax... talking about sliced bread and other craziness. At any rate, for that very reason I'm not going to dwell on this subject too much, instead I'll assume that you've come across this syntax at some point or atleast can grasp it by the simple example below.

//this is not object literal notation
var variable1 = null;
var variable2 = false;

function1(){
// some code
}

function2(){
// some code
}

// the above becomes object literal notation below... 

var SomeVariableName = {

    variable1: null,
    variable2: false,

    init:function(){
    },

    function1:function(){
    // some code
    },

    function2:function(){
    // some code
    }
}

Like most programming languages, in JavaScript there exist a large number of stylistic preferences and "best practices." When working with MooTools you'll find there to be no shortage of these, including: not chaining excessively, capitalizing your class names, comma separating variable declarations, etc.... However, among these, object literal notation is perhaps most fundamental to understanding not only the way in which the MooTools framework itself is structured, but actually how to take advantage of this framework in developing your own code. We'll develop this idea further throughout the rest of this article and as you'll see, all the examples from this point forward will be taking advantage of this syntax.


3. The Class Constructor

step 3

If JavaScript doesn't have "classes," then why is there all this hype around Motools and classes? In May of last year, Aaron Newton published an excellent comparative piece on jQuery and MooTools. Among other things, he addressed precisely this question of classes in a very succinct way: "Despite its name, the MooTools Class function is not really a class nor does it create them. It has design patterns that might remind you of classes in a more traditional programming language, but really Class is all about objects and prototypal inheritance."
As Aaron goes on to detail, the MooTools framework is pushing for powerful and ultimately simple ways to organize and structure your code, ways which are elegant but also familiar, and not just semantically, but in their capacity to behave in classical design patterns. In fact, you'll find utilizing "classes" in your code base opens up your code to many powerful programming patterns: the mediator, the mixin, etc...

A simple MooTools class will look something like this (notice the syntax):

var YourClass = new Class({

    variable1: false,

    initialize: function(){
        this.toggleVariable();
    },

    toggleVariable: function(){
        this.variable1 = !variable1;
    }

});

var yourClassInstance = new YourClass();
yourClassInstance.toggleVariable(); // this.variable1 == false

Not too complicated, right? Once you begin structuring your code in classes like these, you'll find that your code repository will become not only a lot more organized and manageable, but actually smaller!


4. Class.Mutators

step 4

So how exactly does it become smaller? Returning to JavaScript's prototypal inheritance model and how it relates to the Class constructor, MooTools provides us with Extends and Implements. As properties, both are fundamental to the production of your MooTools subclasses and make this whole protyping mess a bit more intuitive. At a high level, Extends gives your subclass access to all the methods of it's base class, where methods and properties of the same name are overwritten (not to worry, they're still accessible through the parent() method). Similar to Extends, Implements adopts properties from one or more other classes, but without the inheritance model.

Consider briefly Digitarald's fancy upload plugin for Mootools. In this program Harald defines several classes, one of which is called the 'File' class. File houses the core functionality that a file object needs to interface with his uploading program and for this very reason is perfect for being extended; one might create an "Image File" subclass, a "Text File" subclass, etc. By modeling your code in this way, you are able to build your code up, rather than out. Consider the example below for how to use Extends:

var YourSubClass = new Class({

    Extends: YourClass, //here we are extending "YourClass" from our previous example

    variable2: false,

    initialize: function(){
        this.parent(); // this will call the initialize function from the bass Class "YourClass"
    },

    //here we are overwriting the toggle Variable function of "YourClass" with a new function
    toggleVariable: function(){
        this.variable1 = !variable1; // notice variable1 from "YourClass" is still accessible in YourSubClass
        this.variable2 = !this.variable1;
    }
});

5. Custom Events and Options

step 5

The most common usecase I find with Implements is including either the Events constructor or the Options constructor in my classes. As the name suggests, implementing Events allows for both the attachment and firing of custom events on your object, like onComplete, onFailure, onSuccess, onAnything. This level of abstraction becomes particularly useful when you begin sharing your code across several projects, where events behave as mediators between your current project and your plugins. In this way you can finally get away from those nasty one-to-one, bound relationships in your plugins. For example:

var YourSubClass = new Class({

    Implements: Events, //here we tell MooTools to implement Events in our sub class (this wont effect the bass "YourClass")

    Extends: YourClass,

    variable2: false,

    initialize: function(){
        this.parent();
    },

    toggleVariable: function(){
        this.variable1 = !variable1;
        this.variable2 = !this.variable1;
        //afterToggle() -- calling "afterToggle" would have made this function a necessary include of YourSubClass
        this.fireEvent('toggled'); //instead a custom event is fired called "toggled"
    }
});

var yourSubClassInstance = new YourSubClass();

var afterToggle = function(){
    alert('i\'ve just been toggled!');
};

//here we add a listener for the custom event, just like we would any other event
yourSubClassInstance.addEvent('toggled', afterToggle);

Besides Events, often you will want to Implement MooTools' Options. This utility class allows you to automate the setting of a list of optional properties to be set on an instance of your class. Again, this can be very helpful when writing plugins for various projects, allowing for the circumstantial customization of certain properties of your object. Consider the example below:

var YourSubClass = new Class({

    //One of the many cool things about the implements property is that it excepts an array.
    Implements: [Events,Options], //Here we include Options

    Extends: YourClass,

    //options are set if the invoker does not explicitly specify a value.
    options: {
        variable2: false
    },

    initialize: function(options){
        this.setOptions(options); //sets the options
        this.parent();
    },

    toggleVariable: function(){
        this.variable1 = !variable1;
        this.options.variable2 = !this.variable1;
        this.fireEvent('toggled');
    }
});

// this will start the class with variable2 = true.
var yourSubClassInstance = new YourSubClass({
    variable2: true
});

6. Binding

step 6

As your programs become more complex, a proper understanding of scope becomes invaluable. Scope is the way variables in JavaScript relate to any single point of execution -- there are global variables, which are variables that can be referenced from anywhere in the document and occupy the lowest executing level, local variables, which are variables limited to their immediate containing functions or closures, and finally, self references, the "this" keyword, which are JavaScript's way of referencing the context of the current point of execution.

var global = true; //global variable;

var aFunction = function(){
    var local = true; //local variable
}

$('button').addEvent('click', function(){
    this.addClass('clicked'); // self reference
});

When referencing a variable in your code, JavaScript bubbles from it's current executing position through all accessible levels of variables until it locates the first and nearest occurrence of a positive match. This behavior is often less than desirable, particularly when dealing with events inside of object literals as they house their own self references. Often developers rely on what are called "lexical closures" to circumvent problems like these, storing the self reference in a variable of a different name. However, MooTools provides an alternative means of achieving this through their bind() method, which is not only cleaner, but a lot more elegant. Consider the example below:

...

    addEvents: function(){
        $('button').addEvent('click', function(){
            //binding substitutes the current self reference for that of the object passed in
            this.toggleVariable();
        }.bind(this)); // here we bind this to the click event handler
    },

    toggleVariable: function(){
        //code
    },

...

7. The Element Constructor

step 7

In the example above we targeted an already existing element in the DOM and added an event listener to it. However, it's not uncommon today that you will see entire web apps load their content dynamically using JavaScript. With the evolution of JSON, being able to generate markup on the fly has become increasing necessary. Enter the MooTools Element constructor. The novel thing about this constructor is that it maintains it's readability despite it's large capacity for optional properties (Again, thanks to the object literal notation!). Element accepts an events object, a styles object, plus any individual properties like class, id, src, href, title, etc. That said, it's also loaded with a ton of methods, the complete list of which is available from the MooTools docs here. Below is a simple example of how to get started:

var el = new Element('div', {
    id: 'button',
    'html': 'hellloooo',
    styles: {
        display: 'block',
        position: 'relative',
        float: 'left
    },
    events: {
        click: function(){
            //your code
        }
    }
});

8. DOM Manipulation

step 8

Now that you have your dynamic element, wouldn't it be great to insert it into the DOM? MooTools provides a really handy list of methods for just that, including:

  • inject - places one element relative to the calling element : 'before', 'after', 'top', 'bottom'
  • grab - like inject but in reverse
  • adopt - works like grab accept it can accept an array of elements and you can't specify an exact relation
  • wraps - Works like grab, but instead of moving the grabbed element from its place, this method moves this Element around its target

Of these methods, I've found adopt's ability to accept an array of elements absolutely indispensable, especially when structuring larger quantities of dynamic markup. Consider the example below:

var el = new Element('div', {
    id: 'button',
    styles: {
        display: 'block',
        position: 'relative',
        float: 'left
    },
    events: {
        click: function(){
            //your code
        }
    }
}).adopt(

    this.createSpan(), // returns an element which can later be overwritten by a subclass

    new Element('a', {
        href: 'http://somewebsite.com'
    }).adopt(

        new Element('strong', {
            'html': 'world'
        })

    )
).inject($(document.body),'top');

The example above makes for a truly object oriented approach to DOM manipulation. When you become a super MooTools ninja, jedi, junky, nerd, you can use the method above to begin abstracting out functions which return elements or arrays of elements, making it possible for your subclasses to target specific methods in modifying your display. Awesome.


9: Request.JSON & Request.JSONP

step 9

JavaScript Object Notation or JSON is the lightweight data-interchange format that everyone loves (especially after working with XML). The great thing about JSON of course is that it's structure is recognized natively by JavaScript, and with many large sites opening up their data to the public via APIs, there's really no reason why you shouldn't invest the time to get familiar with it. No longer a cross browser nightmare, whether you're pushing data to a back-end service or requesting another batch of tweets from twitter, the MooTools Request constructor makes JSON and JSONP incredibly simple. It works with several event listeners and recently a timeout, which is completely neccessary once you start getting into JSONP. (Which you should! It's so fun.) Here's a simple example:

var JSONRequest = new Request.JSON({
    url: "http://yoursite.com/tellMeSomething.php",
    onFailure: function(){
        alert('oh nooo!');
    },
    onSuccess: function(response){
        alert('hooray!: ' + response.result);
    }
});

10. Fx

step 10

At a high level, the Fx constructor allows you to modify any CSS property of an HTML element, which itself accepts a single element and a series of optional properties (duration, transition type, etc.) to create smooth animation effects of colors, slides, scrolls, etc. What's more, the Fx constructor is fully compatible with Robert Penner's Easing equations, which are a great way to add a touch of uniqueness to your transitions like bounce, elastic, sin, etc.

If you're "hardcore" you can actually achieve all of the animation effects using either Fx.Tween(single css style animation) or Fx.Morph (multiple simultaneous style animations). Of course, beyond these there's Fx.Slide, Fx.Scroll, Fx.Accordian, etc. Here's a simple example using Fx.Tween:

var myFx = new Fx.Tween($('button'));
myFx.start('background-color', '#000', '#f00'); //this tweens the background color of the button element.

If you're dying to get deeper into this topic, check out Consider Open's fx tutorial for a fairly comprehensive introduction to the constructor.


11. Swiff

step 11

Originally appearing in Digitarald's fancy upload, the Swiff object allows your page's JavaScript to communicate with Flash. This makes it substantially easier to interact with Flash's unique functionality like video, sound, file streaming, and clipboard accessing features. More over, Swiff allows you to pass values and manipulate the Flash movie using conventions you're familiar with from JavaScript and Mootools. Integrating flash in this way is particularly useful as we begin taking steps towards offering HTML5 as a progressive enhancement, where, barring user's have the flash plugin, Swiff can be used to control audio or video on older browsers. Meanwhile, check out the simple example below:

var flashObject = new Swiff('sounds.swf', {
    id: 'mySoundManager',
    width: 1,
    height: 1,
    vars: {
        myVariable: true, //pass variables into flash on load
    },
    callBacks: {
        //call custom events from your flash object
        someEvent: function(){
            //code
        }
    }
});

Swiff.remote(flashObject, 'playMySound') //calls the function "playMySound" from within flash

12. Mootools More & Forge

step 12

Now with over fifteen members contributing to the official more plugin repository and over one hundred unofficial plugins already on Forge, it's no surprise that "Community" is what the MooTools team wanted us as developers to take away from 2009. Indeed people have truly embraced this framework, and now with Forge, we have a great place to meet each other and begin sharing ideas. You'll find David Walsh, Aaron Newton, 3n, and many others actively contributing amazing code and facilitating an environment capable of both inspiration and utility. In the end, the most helpful way to pick up the MooTools framework is by engaging with the developers around you and ultimately understanding what they are working on and how they're going about it.

Write a Plus Tutorial

Did you know that you can earn up to $600 for writing a PLUS tutorial and/or screencast for us? We're looking for in depth and well-written tutorials on HTML, CSS, PHP, and JavaScript. If you're of the ability, please contact Jeffrey at nettuts@tutsplus.com.

Please note that actual compensation will be dependent upon the quality of the final tutorial and screencast.

Write a PLUS tutorial
]]>
http://net.tutsplus.com/tutorials/javascript-ajax/12-steps-to-mootools-mastery/feed/ 25
Quick Tip: Learning jQuery 1.4’s $.proxy http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-learning-jquery-1-4s-proxy/ http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-learning-jquery-1-4s-proxy/#comments Mon, 01 Mar 2010 18:50:05 +0000 Jeffrey Way http://net.tutsplus.com/?p=9629 ]]> One of my favorite new features in jQuery 1.4 is the new $.proxy method. It allows us the ability to force a particular context when calling a method. In JavaScript, there can be times when it’s difficult to hold on to the this keyword. For example, when it’s bound to some event handler, this now refers to the target of the handler, rather than your desired object.

If this sounds a bit confusing, don’t worry; today’s four-minute video quick tip should clear things up.

// Create an object.
var obj = {
        // this = obj
	somevar : 'some value',

	doSomething : function() {
		alert(this.somevar);
	}
};

// When bound to an event handler, this will
// refer to the target of the handler, or the div - not obj.
$('div').click(obj.doSomething); // undefined. 

// With $.proxy, we pass two parameters.
// 1. The method to call.
// 2. The context.
// In this case, we're forcing obj to once again be equal to this.
$('div').click( $.proxy(obj.doSomething, obj) ); // some value

Be sure to refer to the jQuery API for more information on $.proxy!

]]>
http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-learning-jquery-1-4s-proxy/feed/ 29
Coding your First jQuery UI Plugin http://net.tutsplus.com/tutorials/javascript-ajax/coding-your-first-jquery-ui-plugin/ http://net.tutsplus.com/tutorials/javascript-ajax/coding-your-first-jquery-ui-plugin/#comments Wed, 24 Feb 2010 17:55:54 +0000 Dan Wellman http://net.tutsplus.com/?p=9460 ]]> jQuery contains the fn.extend() method, which makes authoring jQuery plugins quite easy, allowing us to write code that is used in exactly the same way as other jQuery methods. jQuery UI also contains structures that make authoring custom jQuery UI plugins easy. So that’s what we’ll be looking at over the course of this tutorial. The methods used differ from that of standard jQuery plugins, and there are stricter conventions that should be followed, which is why I feel the topic is deserving of an article.


Over the course of this tutorial, I’ll show you the coding conventions and general guidelines that should be adhered to when authoring plugins for jQuery UI. We’ll be creating a simple plugin that just adds captions to images on the page. It’s purposely simple so that we can focus on what is needed to make a jQuery UI plugin without getting lost in the code. Anyone that’s written a jQuery plugin should have no problems. Knowledge of jQuery UI may help but shouldn’t be essential to complete this tutorial. Let’s get started.

Getting Started

We’ll need a copy of jQuery as well as a couple of files from jQuery UI, but it needs to be jQuery UI 1.8 (this can be found on the blog). Create a working directory somewhere on your machine called jqueryui-plugin, then inside this create a css folder, a js folder and an img folder (the images used in this tutorial can be found in the code download).

Download the library and unpack it somewhere accessible. We only need a few files from the archive, namely the jQuery source file which is in the root of the archive as jquery-1.4.1.js, and the jquery.ui.core.js and jquery.ui.widget.js files, which are both in the ui folder. Grab these and put them into the js folder in your working directory. We’ll be making light use of the CSS framework as well, so we’ll need one of the theme style sheets available with the current stable version of jQuery UI (I used ui-lightness in this example).

We’ll be making a captionator widget, so we’ll also need a page, with a bunch of images on it, to develop/test the plugin with. This example uses the following page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<title>jQuery UI Captionator</title>
		<link rel="stylesheet" type="text/css" href="css/ui-lightness/jquery-ui-1.7.2.custom.css">
		<link rel="stylesheet" type="text/css" href="css/ui.captionator.css">
	</head>
	<body>
		<img src="img/1.jpg" alt="Royal Air Force Eurofighter Typhoon">
		<img src="img/2.jpg" alt="A British military GR-9 Harrier">
		<img src="img/3.jpg" alt="Two RAF Tornado GR-4s pull away from a KC-135 Stratotanker after refueling">
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript" src="js/jquery.ui.core.js"></script>
		<script type="text/javascript" src="js/jquery.ui.widget.js"></script>
		<script type="text/javascript" src="js/jquery.ui.captionator.js"></script>
	</body>
</html>

We’ll keep things pretty simple for now; we’ve just three images on the page, followed by four script files; three link to the jQuery and jQuery UI source files, the fourth to our plugin’s source file which we’ll create shortly. The jquery.ui.core.js file is required by all jQuery UI widgets/plugins. The jquery.ui.widget.js file is the widget factory and allows for the creation of consistent widgets that share common API functionality. Most library components require this, and we’ll be using it to create our plugin.

Creating the Plugin File

Create a new JavaScript file and save it as jquery.ui.captionator.js in the js folder; we should keep to jQuery UI’s naming convention, which has just been updated in the 1.8 version of the library, and use jquery.ui.plugin_name.js. Add the following code to the new file:

(function($) {

})(jQuery);

All of the code that makes up our plugin should be encapsulated within a self-executing anonymous function. The jQuery object is passed into this function and is used inside the function via the $ alias; this is to ensure that the plugin is compatible with jQuery’s noConflict() method. This is a specified requirement and should always be adhered to.

Next we need to define the plugin; add the following code to our anonymous function:

$.widget("ui.captionator", {

});

The pattern for using the widget factory is simple to use, we just call the widget() method specifying the name of the plugin as the first argument, and an object literal containing the properties and methods that make the plugin function. This allows our plugin to be called (and created) using the commen jQuery syntax $(“element_caption_applied_to”).captionator(); like any other jQuery or jQuery UI method.

The widget factory provides a number of these properties and methods for us; for example, we can set the default options for the plugin using the options property, and add an initialisation function that is executed automatically by the widget factory as soon as an instance of the plugin is invoked. Within the object that appears as the second argument in the previous code add the following code:

options: {
  location: "bottom",
  color: "#fff",
  backgroundColor: "#000"
},

These are the only options we’ll use in our example plugin; users (and by users I mean implementers, not end users) of the plugin can specify the position of the caption to be either at the top of the image it is called on, or the bottom, they can specify the color of the text on the caption, or change the background-color of the caption. To change a configurable option of any jQuery UI widget prior to initialisation the implementing developer would just use something like this:

$(“element_caption_applied_to”).captionator({ location: “top” });

Next we can create our initialisation function, after the options object add the following method:

_create: function() {

	var self = this,
		o = self.options,
		el = self.element,
		cap = $("<span></span>").text(el.attr("alt")).addClass("ui-widget ui-caption").css({
			backgroundColor: o.backgroundColor,
			color: o.color,
			width: el.width()
		}).insertAfter(el),
		capWidth = el.width() - parseInt(cap.css("paddingLeft")) - parseInt(cap.css("paddingRight")),
		capHeight = cap.outerHeight() - parseInt(cap.css("paddingTop")) + parseInt(cap.css("paddingBottom"));

	cap.css({
		width: capWidth,
		top: (o.location === "top") ? el.offset().top : el.offset().top + el.height() - capHeight,
		left: el.offset().left,
		display: "block"
	});

	$(window).resize(function(){
		cap.css({
			top: (o.location === "top") ? el.offset().top : el.offset().top + el.height() - capHeight,
			left: el.offset().left
		});
	});
},

The method name should begin with an underscore as jQuery UI prevents any plugin method that begins with an underscore from being called from outside of the plugin, so this stops it being accidentally called from the HTML page. Any method that we begin with an underscore will be protected in this way.

The majority of our initialization method is a series of variables; within our function the keyword this refers to an object passed into the method which represents the instance of the plugin. The first variable caches a reference to the current instance of the plugin; the _create method is called for each element that the plugin method is called on, which could be a single element or several.

We can access the default options of the plugin (which are overridden automatically if the implementer configures any of them) using the options property of the object; we cache this in the second variable. The element that the plugin method (captionator()) was called on, which in this example would be an image, can be accessed using the element property of the object. We store this in the third variable.

We use the fourth variable to store a reference to the new caption element, which is built from a simple <span>; the <span> has its innerText set to the alt attribute of the current image, and several class names are added to it; we give it the ui-widget class name so that it can pick up some default styling from the current jQuery UI theme. We also give it a custom class name so that we can add some of our own styling.

Next we need to set some CSS properties; we’ll be using a separate style sheet for some styles, but certain things, such as the color and background-color styles are controllable via configurable options, so we need to set these using the plugin. The width of the caption needs to match the width of the image that it overlays, so we also need to determine this and set it programmatically. Finally the new <span> is injected into the page directly after the target image.

Once the caption has been inserted, it needs to be sized and positioned; the only way it can be sized accurately is if it already exists in the DOM and has CSS rules applied to it, such as the font-size. This is why we append the caption to the page, and then determine its exact dimensions, which are then stored in the variables capWidth and capHeight.

Once the caption has been appended to the page (and only then) we can work set the correct width, height and position of each caption, which we set using the css() method once again. The captions are actually completely separate from the images; they are inserted directly after each image and then positioned to appear to overlay the images, after all, we can’t append the <span> as a child of the <img>.

This is fine, until the browser is resized, at which point the images move but the captions don’t because they are absolutely positioned. To remedy this, we’ve used a basic resize handler attached to the window which simply repositions each caption to the new position of its image. This event handler is the last thing in our initialization method.

Another method that our plugin should expose is the destroy() method which is common to all jQuery UI plugins. We must provide an implementation of this method in order to clean up after our plugin. For our example plugin, the method can be as simple as this:

destroy: function() {
	this.element.next().remove();

	$(window).unbind("resize");
},

All we need to do is remove the captions and unbind our window resize handler. This method can be called by an implementer using the plugin so we shouldn’t begin this method name with an underscore. To call this method, the implementer would use $(“element_caption_attached_to”).captionator(“destroy”); which is how any of our public methods would be called.

We need to provide another method controlled/executed by the widget factory; we saw earlier how a developer could change a configurable option prior to initialisation, but what about after initialisation? This is done using the option method using the following syntax: $(“element_caption_attached_to”).captionator(“option”, “location”, “top”); so we need to add the built-in method _setOption to handle this:

_setOption: function(option, value) {
	$.Widget.prototype._setOption.apply( this, arguments );

	var el = this.element,
		cap = el.next(),
		capHeight = cap.outerHeight() - parseInt(cap.css("paddingTop")) + parseInt(cap.css("paddingBottom"));

	switch (option) {
		case "location":
			(value === "top") ? cap.css("top", el.offset().top) : cap.css("top", el.offset().top + el.height() - capHeight);
			break;
		case "color":
			el.next().css("color", value);
			break;
		case "backgroundColor":
			el.next().css("backgroundColor", value);
			break;
	}
}

We start this method with an underscore because the implementer uses option, not _setOption to actually change the options; we don’t need to worry about how this is handled, we just need to provide this method to deal with anything specific to our plugin. Because this method already exists in the widget factory we should call the original method, which we do first of all in our method using the prototype of the Widget object, specifying the method name (_setOption in this case but we could do it for other built-in methods as well) and use apply to call it. We can then proceed with the code specific to our plugin.

The function will automatically receive two arguments which are the option to change and the new value. We cache some commonly used elements, such as the image and the caption, and obtain the current height of each caption. We then use a simple switch-case statement to handle each of our three options being changed. Repositioning the captions is the most complex, but is still quite trivial and similar to how we positioned them initially.

Adding Events

It’s important to add events that developers using your plugin can add callbacks for so that they can react to different things happening when users interact with the widget in some way. The widget factory handles most of this task for us, all we need to do is trigger the event. This plugin doesn’t really do much, but we could still trigger an event after each caption is added to the page; to do this add the following code directly before the resize event handler:

self._trigger("added", null, cap);

That’s all we need to do! A single line of code and we have a custom event that can be reacted to. We call the _trigger() method of the plugin instance (which we stored in the variable self) and pass the method three arguments; the first is the name of the event, the second is for the event object (we don’t need to use this in our example plugin, hence the null value) and the third is a reference to the caption element. The widget factory will automatically pass the event object (if supplied) and the data we pass in the third parameter to a callback function that uses the added event. A developer could hook into this event using the following syntax: $(“element_caption_attached_to”).captionator({ added: function(e, ui){ //do stuff });

Styling the Plugin

We only need a very tiny style sheet for our plugin, literally we have just three styles. It’s almost not even worth creating a separate file for the styles! But we will, so create a new file called ui.captionator.css, which is the required format for plugin style sheets, and save it in the css directory. Add the following styles to it:

.ui-caption { display:none; position:absolute; padding:10px; }

That’s all there is to it. Our plugin is now functionally and visually complete. The captions should appear like this:

Final Product

Summary

Like jQuery’s plugin creation method fn.extend(), jQuery UI also has its own mechanism that allows developers to quickly and easily write robust and scalable plugins that meet the jQuery UI projects high standards, although in terms of what it actually does for us, it’s even better that jQuery. The widget factory has been created in such a way that pretty much all of the hard work is taken out of custom plugin creation.

It’s easy to work with the methods provided by the widget factory to add methods to our plugins that are common across UI widgets, such as the destroy and option methods, which implementing developers would expect to find in any plugin. We also saw just how easy it is to trigger custom events that developers can use to react to interactions or occurrences with the widget.

]]>
http://net.tutsplus.com/tutorials/javascript-ajax/coding-your-first-jquery-ui-plugin/feed/ 35