Information

1 Sep 10

One of the more interesting and fun aspects of iPad usage is the ability to effect change in a webpage by swiping a finger across the screen of the iPad. For example, swiping to the left to navigate to the next page in a series of pages, or swiping to display the next image in a series of images. For iPad users, these actions are intuitive and natural.

However, for those who compose webpages, adding touch detection to a page can be a challenging and difficult process. No more. The information presented on Padilicious: Add Finger-Swipe Support to Webpages, will make it easy to add touch sensing to your pages, requiring only a minimum of JavaScript coding on your part.

touch-script


Filed under: ASP,Component,Design,Fonts,Framework,Information,JavaScript,License Free,Ping,Script

Trackback Uri




27 Aug 10

Polymaps is a display and interaction library for tile-based vector and raster maps using SVG and Javascript. Their intent is to provide a minimal, extensible, customizable, and free display library for discriminating designers and developers who want to use interactive maps in their own projects.

Polymaps provides speedy display of multi-zoom datasets over maps, and supports a variety of visual presentations for tiled vector data, in addition to the usual cartography from OpenStreetMap, CloudMade, Bing, and other providers of image-based web maps

Polymaps can load data at a full range of scales, it’s ideal for showing information from country level on down to states, cities, neighborhoods, and individual streets. Because Polymaps uses SVG (Scalable Vector Graphics) to display information, you can use familiar, comfortable CSS rules to define the design of your data. And because Polymaps uses the well known spherical mercator tile format for its imagery and its data, publishing information is a snap.

polymaps

http://polymaps.org/


Filed under: CSS,Charts,Component,Design,Icons,Information,JavaScript,Script,Tools

Trackback Uri




27 Aug 10

In this tutorial, we are using jQuery UI’s autocomplete widget, to build a simple AJAX movie search form. The script is going to use TheMovieDatabase.org‘s free API, to provide auto suggestions against a vast database of movie titles.

For those of you who might not be familiar with TMDb.org, this is an open, community driven movie database. It is similar to IMDb, which you’ve probably heard about, but also provides a number of useful API’s for developers.

Prerequisites

Before being able to use the API, you need to get a free developer key from TMDb after a quick registration. After this, remember to copy your key to movieInfo.php from the download archive.

Step 1 – XHTML

The markup consists of  the two main div containers – #logo and #holder. The former holds the icon and the logo text in the form of transparent PNG images (defined as backgrounds to the respective divs), while the latter contains the search form and the submit button.

movieApp.html






Notice that the action attribute of the form is pointed at TMDB’s search page. The search terms are passed via POST with the #movieName text field. You can test it by filling in a movie name and submitting the form.

Lastly in the page are included jQuery, jQuery UI and our own script file. We are using jQuery UI’s autocomplete widget to display a drop down list of movie titles which are fetched from TMDb’s API. You can see the markup that is generated by the widget below.



This code is generated automatically by the widget and appended before the closing body tag.

Simple Movie Search AppSimple Movie Search App

Step 2 – PHP

When you start typing a movie title in the text box of the form, an AJAX request is sent to moveInfo.php. This script sends a search request to TMDb’s API, with our developer key. The service returns a JSON object with suitable movie titles. The script processes them and outputs them back as a response to the AJAX request.

Lets take a closer look at how this works.

movieInfo.php

/**
 *	Define your API key below. To obtain one, visit
 *	http://www.themoviedb.org/account/signup
 */

$api_key = '...';

// If the request was not issued by AJAX, or
// the search term is missing, exit:

if(!$_SERVER["HTTP_X_REQUESTED_WITH"] || !$_GET['term']){
	exit;
}

include 'tmdbAPI/TMDb.php';

$tmdb = new TMDb($api_key);

// Send a search API request to TMDb,
// and parse the returned JSON data:

$json = json_decode($tmdb->searchMovie($_GET['term']));

$response = array();

$i=0;
foreach($json as $movie){

	// Only movies existing in the IMDB catalog (and are not adult) are shown

	if(!$movie->imdb_id || $movie->adult) continue;
	if($i >= 8 ) break;

	// The jQuery autocomplete widget shows the label in the drop down,
	// and adds the value property to the text box.

	$response[$i]['value'] = $movie->name;
	$response[$i]['label'] = $movie->name . ' (' . date('Y',strtotime($movie->released)).')';
	$i++;
}

// Presenting the response as a JSON object:

echo json_encode($response);

Luckily for us, there is a PHP class available, that handles all communication with the TMDb API. We just need to include it into the page, and provide the developer API key we received from TMDb. The search terms, that the user has entered into the search box, are available in $_GET['term']. Calling the searchMovie() method with these terms, will yield a JSON object, containing all kinds of information about the movies that match our search criteria. You can see a sample response below.

[{
    "score": 8.750235,
    "popularity": 3,
    "translated": true,
    "adult": false,
    "language": "en",
    "name": "The Hitchhiker's Guide to the Galaxy",
    "alternative_name": "The Hitchhikers Guide to the Galaxy",
    "movie_type": "movie",
    "id": 7453,
    "imdb_id": "tt0371724",
    "url": "http://www.themoviedb.org/movie/7453",
    "rating": 6.8,
    "certification": "PG",
    "overview": "Mere seconds before the Earth is to be demolished by an alien construction crew, Arthur Dent is swept off the planet by his friend Ford Prefect, a researcher penning a new edition of "The Hitchhiker's Guide to the Galaxy."",
    "released": "2005-04-20",
    "posters": [{
        "image": {
            "type": "poster",
            "size": "original",
            "height": 1000,
            "width": 675,
            "url": "http://hwcdn.themoviedb.org/posters/16e/4bcc96cd017a3c0f2600016e/the-hitchhiker-s-guide-to-the-galaxy-original.jpg",
            "id": "4bcc96cd017a3c0f2600016e"
        }
    }],
    "version": 22,
    "last_modified_at": "2010-07-19 22:59:02"
}]

The response contains the title of the movie, an overview, release date, a corresponding IMDB id, and even posters and fan art. We do not need most of this information, so PHP reduces it only to a title and a release year, after which outputs it in the form of a JSON object, ready to be used by the autocomplete. This brings us to the next step.

Step 3 – jQuery

As you know, jQuery comes with a lot of useful functionality in the form of plugins. There is also a dedicated extension of the library, for building user interfaces, known as jQuery UI. It gives developers widgets, which are ready for use and easy to customize. One of these widgets is the new autocomplete widget, introduced in the newer versions of the library.

Lets take a look at how it is used.

script.js

$(document).ready(function(){

	// Caching the movieName textbox:
	var movieName = $('#movieName');

	// Defining a placeholder text:
	movieName.defaultText('Type a Move Title');

	// Using jQuery UI's autocomplete widget:
	movieName.autocomplete({
		minLength	: 5,
		source		: 'movieInfo.php'
	});

	$('#holder .button').click(function(){
		if(movieName.val().length && movieName.data('defaultText') != movieName.val()){
			$('#holder form').submit();
		}
	});
});

// A custom jQuery method for placeholder text:

$.fn.defaultText = function(value){

	var element = this.eq(0);
	element.data('defaultText',value);

	element.focus(function(){
		if(element.val() == value){
			element.val('').removeClass('defaultText');
		}
	}).blur(function(){
		if(element.val() == '' || element.val() == value){
			element.addClass('defaultText').val(value);
		}
	});

	return element.blur();
}

To create an autocomplete, we just need to call the autocomplete() method. It takes a number of optional parameters. The most important ones are minLength (which prevents request to the server from being fired before a certain number of characters has been typed) and source, which determines the data that is shown in the drop down list.

Source can take either an array with strings, a URL (to which an AJAX request will be sent) or a callback function. In our case, the URL of movieInfo.php will suffice.

Here is a sample response, which is returned by movieInfo.php (this JSON object was compiled after a request to TMDb’s API for “Hitchhiker’s guide“).

[{
    "value": "Hachiko: A Dog's Story",
    "label": "Hachiko: A Dog's Story (2009)"
},
{
    "value": "Teenage Hitch-hikers",
    "label": "Teenage Hitch-hikers (1975)"
},
{
    "value": "The Hitchhiker's Guide to the Galaxy",
    "label": "The Hitchhiker's Guide to the Galaxy (2005)"
},
{
    "value": "The Hitch-Hiker",
    "label": "The Hitch-Hiker (1953)"
}]

Each object in the array contains a value and a label property. The label is only shown in the dropdown list, while the value is inserted into the textbox once the item is selected.

Custom Styled jQuery UI AutocompleteCustom Styled jQuery UI Autocomplete

Step 4 – CSS

Now that all the markup is generated and is in place, it is time to start beautifying.

styles.css – Part 1

#page{
	width:600px;
	margin:150px auto 0;
}

/* Logo */

#logo{
	width:380px;
	position:relative;
	height:90px;
	margin:0 auto;
}

#icon{
	width:80px;
	height:86px;
	background:url('img/icon.png') no-repeat;
	float:left;
}

#movieAppLabel{
	width:268px;
	height:58px;
	background:url('img/logo_txt.png') no-repeat;
	position:absolute;
	right:0;
	top:18px;
}

/* The Search Box & Holder */

#holder{
	width:530px;
	height:145px;
	background:url('img/holder.png') no-repeat center center;
	margin:30px auto;
	position:relative;
}

#holder fieldset{
	position:absolute;
	top:52px;
	left:40px;
	border-bottom:1px solid #fff;
}

#holder input{
	font-family:'Myriad Pro',Arial,Helvetica,sans-serif;
	border:none;
	border-bottom:1px solid #bbb;
	background:none;
	color:#8D8D8D;
	font-size:20px;
	padding:4px 0;
	width:250px;
	text-shadow:1px 1px #fff;
	outline:none;
}

In the first part of the code, we style the #logo, and the #holder divs. The shutter icon and the logo text are defined as backgrounds to the #icon and #movieAppLabel divs respectively. Relative positioning is applied to the #holder so that it is easier to position the input box and the submit button.

styles.css – Part 2

fieldset{
	border:none;
}

/* The Blue Button */

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

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

/* Styling the markup generated by the autocomplete jQuery UI widget */

ul.ui-autocomplete{
	width:250px;
	background-color:#f5f5f5;
	border:1px solid #fff;
	outline:1px solid #ccc;
}

ul.ui-autocomplete li{
	list-style:none;
	border-bottom:1px solid #e0e0e0;
	border-top:1px solid #fff;
}

ul.ui-autocomplete li:first-child{
	border-top:none;
}

ul.ui-autocomplete li:last-child{
	border-bottom:none;
}

ul.ui-autocomplete li a{
	color:#999;
	border:none !important;
	text-decoration:none !important;
	padding:10px 17px;
	display:block;
}

#ui-active-menuitem{
	background-color:#fff;
	color:#666;
	cursor:pointer;
}

jQuery UI does come with its own styles, however they are rather clunky and do not fit well into the current design. This is why we are applying a number of rules (starting from line 23), which apply a custom design to the autocomplete widget. The structure of the widget is basically an unordered list, with each of the suggested items being a hyperlink in a li element. With this in mind (and after looking up the appropriate class names from the code in step one) we can safely style the drop down list and perfectly blend it with the rest of the design.

With this our Simple Movie Search App is complete!

To Wrap it Up

You can modify this script to use any kind of api and data. This can be a powerful tool, as it might assist users in typing search terms that they may not normally think of themselves. For example providing your product names as search suggestions, may be an effective tactic to expose more of your merchandise and improve sales.

What do you think? How would you improve this app?


Filed under: Buttons,CSS,Design,Efect,Information,Menu,PHP,Ping,Script,Tutorial,Upload,jQuery

Trackback Uri




27 Aug 10

When you publish something online, there are not that many ways to determine whether people like what you have to say. Comments, the cornerstone of blogging, are too demanding, and users often prefer not to post one. If you’ve dropped by Behance, you’ve probably noticed their appreciate badge, which is a neat solution to this exact problem. With it people share their appreciation for somebody’s work.

Today we are implementing such a badge, which you can include in every page of your website with a bit of jQuery magic. So go ahead and download the zip from the button above (PSD included!) and continue with the tutorial.

The Database Schema

The script we are doing today uses two tables. The first holds one record for each of the pages which have the appreciate button enabled. The second one stores the IP of the person that voted along the unique ID of the page. This way we can easily determine whether the person has previously voted for the page and display the appropriate version of the button (active or disabled).

Table Schema appreciate_pages

Table Schema appreciate_pages

The hash field holds an MD5 sum of the URL of the page. This way we add an UNIQUE index which will speed up the selects we run on the records, as well ensure there are no duplicate records in the table. The appreciated column holds the number of appreciations of the pages.

Table Schema appreciate_votes

Table Schema appreciate_votes

The appreciate_votes table contains the IP of the person that has voted (in the form of an integer), and the id of the page from the appreciate_pages table. The timestamp is automatically updated to the current time when an insert occurs.

You can create these two tables by running the code from tables.sql in the SQL section of phpMyAdmin from the downloadable archive, part of this tutorial.

Step 1 – XHTML

Lets start with the XHTML part of the tutorial. The markup of the page is extremely simple. To have the appreciate button functioning, you just need to provide a container in which the button is inserted, and an optional element, which holds the total number of clicks on the button. You can safely omit the latter one, leaving you with only one div to code.

page.html










In the page above, you can see that I am including two stylesheet files. The first is styles.css, which is used to style the page, and appreciate.css, which is located in the plugin directory, and is responsible for the styling of the appreciate button.

Before the closing body tag, you can see that I also include the jQuery library from Google’s CDN repository, the plugin.js file and script.js, which uses the plugin to create the button on the page. You will only need to change the contents of script.js to make the script working on your pages.

Click To Appreciate Button

Click To Appreciate – looks good on both dark and light backgrounds

Step 2 – PHP

PHP handles the database interactions and is on the backend of the AJAX requests. Most of the script logic is located in c script.php which you can see below. But first lets take a look at connect.php, which handles the database connection.

appreciateMe/connect.php

$db_host = 'localhost';
$db_user = 'YourUsername';
$db_pass = 'YouPassword';
$db_name = 'NameOfDB';

@$mysqli = new mysqli($db_host, $db_user, $db_pass, $db_name);

if (mysqli_connect_errno()) {
	die('

Could not connect to the database

'); } $mysqli->set_charset("utf8");

Up until now, we’ve always used the old mysql extension for database connections under PHP, as it is a bit easier to use and I wanted to keep the code compatible with PHP 4. However, with the recent announcement that WordPress (our favorite blogging engine) will be dropping support for that version of PHP, I decided that it is time to also make the switch to the new version – MySQLi (MySQL improved).

As you can see from the code above, the only major difference with the old way we connected to a database, is that here we create a MySQLi object instead of using the mysql_ functions. Also, as you will see in a moment, when we query the database a MySQL resource object is returned, which in turn has its own set of methods. This might sound intimidating, but it will become perfectly clear once you see it in action.

appreciateMe/script.php

/* Setting the error reporting level */
error_reporting(E_ALL ^ E_NOTICE);
include 'connect.php';

if(!$_GET['url'] || !filter_input(INPUT_GET,'url',FILTER_VALIDATE_URL)){
	exit;
}

$pageID			= 0;
$appreciated	= 0;
$jsonArray		= array();
$hash			= md5($_GET['url']);
$ip				= sprintf('%u',ip2long($_SERVER['REMOTE_ADDR']));

// $result is an object:
$result = $mysqli->query("SELECT id,appreciated FROM appreciate_pages WHERE hash='".$hash."'");

if($result)
{
	list($pageID,$appreciated) = $result->fetch_row();
	// fetch_row() is a method of result
}

// The submit parameter denotes that we need to write to the database

if($_GET['submit'])
{
	if(!$pageID)
	{
		// If the page has not been appreciated yet, insert a new
		// record to the database.

		$mysqli->query("
			INSERT INTO appreciate_pages
			SET
				hash='".$hash."',
				url='".$mysqli->real_escape_string($_GET['url'])."'"
		);

		if($mysqli->affected_rows){

			// The insert_id property contains the value of
			// the primary key. In our case this is also the pageID.

			$pageID = $mysqli->insert_id;
		}
	}

	// Write the vote to the DB, so the user can vote only once

	$mysqli->query("
		INSERT INTO appreciate_votes
		SET
			ip = ".$ip.",
			pageid = ".$pageID
	);

	if($mysqli->affected_rows){
		$mysqli->query("
			UPDATE appreciate_pages
			SET appreciated=appreciated+1 WHERE id=".$pageID
		);

		// Increment the appreciated field
	}

	$jsonArray = array('status'=>1);
}
else
{
	// Only print the stats

	$voted = 0;

	// Has the user voted?
	$res = $mysqli->query("
		SELECT 1 FROM appreciate_votes
		WHERE ip=".$ip." AND pageid=".$pageID
	);

	if($res->num_rows){
		$voted = 1;
	}

	$jsonArray = array('status'=>1,'voted'=>$voted,'appreciated'=>$appreciated);
}

// Telling the browser to interpret the response as JSON:
header('Content-type: application/json');

echo json_encode($jsonArray);

The script handles two different types of AJAX requests – read only request (which returns a JSON object with information about the number of appreciations of the page, and whether the current user has clicked the button), and write requests (which save the visitor’s vote to the database, and if necessary, save the page URL and hash as well).

As you an see in the code snippet above, one of the first things that the script does is to calulate the MD5 hash of the page. This is used as a unique key in the database, as URLs have unlimited length which is incompatible with MySQL’s UNIQUE keys. As an MD5 hash is unique for most practical purposes, we can safely use it in our selects and inserts, instead of the long URL addresses.

In the last line of the code, we convert the $jsonArray array into a valid JSON object with the inbuilt json_encode PHP function, and output it with a applicatoin/json content type.

Click To Appreciate - Inactive

Click To Appreciate – Inactive

Step 3 – jQuery

Inside the appreciateMe directory you can find the plugin.js file. You must include it in the page you wish to show the Appreciate button on. It uses AJAX to request data from the PHP backend and uses the response it receives to create the markup of the button.

appreciateMe/plugin.js

function(){

	$.appreciateButton = function(options){

		// The options object must contain a URL and a Holder property
		// These are the URL of the Appreciate php script, and the
		// div in which the badge is inserted

		if(!'url' in options || !'holder' in options){
			return false;
		}

		var element = $(options.holder);

		// Forming the url of the current page:

		var currentURL = 	window.location.protocol+'//'+
					window.location.host+window.location.pathname;

		// Issuing a GET request. A rand parameter is passed
		// to prevent the request from being cached in IE

		$.get(options.url,{url:currentURL,rand:Math.random()},function(response){

			// Creating the appreciate button:

			var button = $('',{
				href:'',className:'appreciateBadge',
				html:'Appreciate Me'
			});

			if(!response.voted){
				// If the user has not voted previously,
				// make the button active / clickable.
				button.addClass('active');
			}
			else button.addClass('inactive');

			button.click(function(){
				if(button.hasClass('active')){

					button.removeClass('active').addClass('inactive');

					if(options.count){
						// Incremented the total count
						$(options.count).html(1 + parseInt(response.appreciated));
					}

					// Sending a GET request with a submit parameter.
					// This will save the appreciation to the MySQL DB.

					$.getJSON(options.url,{url:currentURL,submit:1});
				}

				return false;
			});

			element.append(button);

			if(options.count){
				$(options.count).html(response.appreciated);
			}
		},'json');

		return element;
	}

})(jQuery);

The script basically creates a new method in the main jQuery object. This differs from the plugins that we usually do, in that this type of plugins are not called on a set of elements (no need to select elements). You can just call $.appreciateButton() while passing a configuration object as a parameter. This is exactly what we’ve done in script.js add a button to the page:

script.js

$(document).ready(function(){

	// Creating an appreciate button.

	$.appreciateButton({
		url		: 'appreciateMe/script.php',	// URL to the PHP script.
		holder	: '#main',				// The button will be inserted here.
		count	: '#countDiv'			// Optional. Will show the total count.
	});

});

The configuration object, which is passed as a parameter, has to contain a url and a holder properties, whereas count is optional. Notice that I’ve specified the path to script.php relatively, as appreciateMe is a child directory of the one the page is currently in.

However, if you plan to add the script to a site with a variable path structure, you should probably specify an absolute path. Either add a leading slash, or provide a complete URL with http://.

Step 4 – CSS

Now that we have all the markup and code in place, it is time to turn to the styling. The CSS rules that style the appreciate badge are located in appreciate.css. You could optionally copy these rules to your main stylesheet file, if you’d like to avoid the extra request, but beware that you will need to change the paths to the background images.

appreciateMe/appreciate.css

.appreciateBadge{
	width:129px;
	height:129px;
	display:block;
	text-indent:-9999px;
	overflow:hidden;
	background:url('sprite.png') no-repeat;
	text-decoration:none;
	border:none;
}

.appreciateBadge.active{
	background-position:left top;
}

.appreciateBadge.active:hover{
	background-position:0 -129px;
}

.appreciateBadge.inactive{
	background-position:left bottom;
	cursor:default;
}

There are three versions of the appreciate badge image. A default one, a hover one, and an inactive one. All three of these reside in the same file – sprite.png, one below the other. With this technique you can switch between the versions instantaneously by offsetting the background image of the hyperlink.

styles.css

#main{
	margin:80px auto;
	width:130px;
}

#countDiv{
	color:#eee;
	font-size:35px;
	margin-right:120px;
	position:absolute;
	right:50%;
	top:265px;
}

You can find the rest of the styles, which refine the looks of page.html, in styles.css. Only two sets of styles affect the appreciate button directly. The #main div, which contains the button and centers it on the page, and #countDiv in which the total number of appreciations is inserted.

With this our Click to Appreciate Badge is complete!

Conclusion

Before being able to run this script on your server, you first have to replace the MySQL credentials in connect.php with your own. Also, you will need to run the contents of tables.sql in the SQL tab of phpMyAdmin, so the two tables are created. Lastly, depending on your URL paths, you may have to change the URL property of appreciateMe/script.php in the script.js JavaScript File.

Tutorialzine/tutorials/~4/H5YGHZkAUEU" height="1" width="1" />


Filed under: .NET,Announcement,CSS,Comment,Information,JavaScript,MySql,PHP,Ping,Script,Stats,Tech,Tutorial,Upload,Wordpress,jQuery

Trackback Uri




27 Aug 10

Video presentations are a great addition to any product page. With a presentation you can showcase your product’s features without making the visitor read through long paragraphs of text. But apart from producing the video, you still need to manually convert it and find (or code) some sort of flash player that will display it on your site.

The other possible path is that you upload it to a video sharing site such as youtube, but you are going to have a rough time trying to incorporate the player into your design.

Luckily for us, YouTube does provide a solution to this problem – their chromeless player (a stripped down version of the regular embeddable player), which allow you to build and style your own custom controls. This way you have both a quick and secure way to include videos in your pages, and the freedom to customize any way you might want to.

The Idea

Today we are going to make a jQuery plugin which uses YouTube’s chromeless player, and creates our own set of minimalistic controls, which allows for perfect integration with your designs. The supported controls include a Play/Pause/Replay button, and a clickable progress bar.

The plugin is going to use YouTube’s gdata api to determine whether embedding has been allowed for the video, and fetch extensive information about it, such as title, description, tags, screenshots & more, which you can use to improve the plugin.

Using the plugin to embed videos is extremely easy:

// Embed a video into the #player div:
$('#player').youTubeEmbed('http://www.youtube.com/watch?v=u1zgFlCw8Aw');

// Chaining is also supported:
$('#player').youTubeEmbed('http://www.youtube.com/watch?v=u1zgFlCw8Aw');
		.youTubeEmbed('http://www.youtube.com/watch?v=AsdfFdwlzdAw');

You can also specify a width for the embedded video (the height will be calculated automatically depending on the aspect ratio), and choose to disable the progress bar:

$('#player').youTubeEmbed({
	video			: 'http://www.youtube.com/watch?v=u1zgFlCw8Aw',
	width			: 600, 		// Height is calculated automatically
	progressBar	: false		// Hide the progress bar
});

You can grab the plugin from the download button above, and start with the first step.

Step 1 – XHTML

Our plugin depends on jQuery SWFObject to embed the SWF files in the page. Below you can see the combined markup that is generated by both of the plugins.

youtube-player.html

apiplayer?enablejsapi=1&version=3">apiplayer?enablejsapi=1&version=3" name="movie">

The .flashContainerDiv is dynamically created by the plugin for each video on the page. It is populated with the embed code generated by SWFObject, the .controlDiv (which acts as a play/pause button) and the progress bar.

As mentioned above, the insertion of the player itself is handled by the SWFObject plugin. Depending on the browser, it can output either an object element, or a non-standard embed element for IE. This lifts the burden from us and allows us to concentrate on tasks such as querying YouTube’s APIs and building the player controls.

Custom YouTube Player

Custom YouTube Player

Step 2 – jQuery

The plugin’s code is located in the youTubeEmbed-jquery-1.0.js file. However, before being able to use it, you need to include the latest version of the jQuery library in the page, along with the jQuery SWFObject plugin and lastly script.js, which inserts two videos in the demonstration page and handles the submissions of the preview form.





Before we start digging into the player plugin’s code, lets take a look at a sample response from YouTube’s gdata api. It can give you a lot of useful information about a video, including duration, access control (both of which used by the plugin) and all sorts of additional data such as title, description, tags, screenshots and more.

Sample JSON response

{
    "id": "u1zgFlCw8Aw",
    "uploaded": "2008-03-05T01:22:17.000Z",
    "updated": "2010-07-23T01:02:42.000Z",
    "uploader": "GoogleDevelopers",
    "category": "People",
    "title": "The YouTube API: Upload, Player APIs and more!",
    "description": "Listen to the YouTube APIs and Tools team talk about...",
    "tags": ["youtube", "launch", "api", "engineering"],
    "thumbnail": {
        "sqDefault": "http://www.appwebmaster.com/wp-content/uploads/2010/08/4d39b312feefault.jpg.jpg",
        "hqDefault": "http://i.ytimg.com/vi/u1zgFlCw8Aw/hqdefault.jpg"
    },
    "player": {
        "default": "http://www.youtube.com/watch?v=u1zgFlCw8Aw",
        "mobile": "http://m.youtube.com/details?v=u1zgFlCw8Aw"
    },
    "content": {
        "1": "rtsp://v4.cache5.c.youtube.com/CiILE..",
        "5": "http://www.youtube.com/v/u1zgFlCw8Aw?f..",
        "6": "rtsp://v3.cache4.c.youtube.com/CiILENy73.."
    },
    "duration": 259,
    "location": "san bruno, ca",
    "rating": 4.3,
    "likeCount": "119",
    "ratingCount": 144,
    "viewCount": 251024,
    "favoriteCount": 164,
    "commentCount": 118,
    "accessControl": {
        "syndicate": "allowed",
        "commentVote": "allowed",
        "rate": "allowed",
        "list": "allowed",
        "comment": "allowed",
        "embed": "allowed",
        "videoRespond": "allowed"
    }
}

All the fields of this response objects are available as properties in the data variable (data.fieldname). You could potentially modify the plugin to show the title with a link to the video page on youtube, or show the rating of the video.

Now lets dive directly into the script’s source code.

youTubeEmbed-jquery-1.0.js – Part 1

(function($){

	$.fn.youTubeEmbed = function(settings){

		// Settings can be either a URL string,
		// or an object

		if(typeof settings == 'string'){
			settings = {'video' : settings}
		}

		// Default values

		var def = {
			width		: 640,
			progressBar	: true
		};

		settings = $.extend(def,settings);

		var elements = {
			originalDIV	: this,	// The "this" of the plugin
			container	: null,	// A container div, inserted by the plugin
			control		: null,	// The control play/pause button
			player		: null,	// The flash player
			progress	: null,	// Progress bar
			elapsed		: null	// The light blue elapsed bar
		};

		try{	

			settings.videoID = settings.video.match(/v=(w+)/)[1];

			// safeID is a stripped version of videoID,
			// ready for use as a JavaScript function name

			settings.safeID = settings.videoID.replace(/[^a-z0-9]/ig,'');

		} catch (e){
			// If the url was invalid, just return the "this"
			return elements.originalDIV;
		}

		// Fetch data about the video from YouTube's API

		var youtubeAPI = 'http://gdata.youtube.com/feeds/api/videos?v=2&alt=jsonc';

		$.get(youtubeAPI,{'q':settings.videoID},function(response){

			var data = response.data;

			if(!data.totalItems || data.items[0].accessControl.embed!="allowed"){

				// If the video was not found, or embedding is not allowed;

				return elements.originalDIV;
			}

			// data holds API info about the video:

			data = data.items[0];

			settings.ratio = 3/4;
			if(data.aspectRatio == "widescreen"){
				settings.ratio = 9/16;
			}

			settings.height = Math.round(settings.width*settings.ratio);

We start by defining our script as a jQuery plugin by adding it as a function to the $.fn object. To make the code easier to follow and read, I put all the elements of the page, such as the control and the progressBar divs in a structure called elements.

After extracting the id of the video (a unique 11 character sequence after the ?v= parameter), we send a JSONP request to youtube’s gdata API. Depending on whether such a video exists, and on whether embedding is allowed on it, we proceed with calculating the aspect ratio. The height of the video is calculated by using this ratio and multiplying it to the width.

youTubeEmbed-jquery-1.0.js – Part 2

			// Creating a container inside the original div, which will
			// hold the object/embed code of the video

			elements.container = $('
',{className:'flashContainer',css:{ width : settings.width, height : settings.height }}).appendTo(elements.originalDIV); // Embedding the YouTube chromeless player // and loading the video inside it: elements.container.flash({ swf : 'http://www.youtube.com/apiplayer?enablejsapi=1&version=3', id : 'video_'+settings.safeID, height : settings.height, width : settings.width, allowScriptAccess:'always', wmode : 'transparent', flashvars : { "video_id" : settings.videoID, "playerapiid" : settings.safeID } }); // We use get, because we need the DOM element // itself, and not a jquery object: elements.player = elements.container.flash().get(0); // Creating the control Div. It will act as a ply/pause button elements.control = $('
',{className:'controlDiv play'}) .appendTo(elements.container); // If the user wants to show the progress bar: if(settings.progressBar){ elements.progress = $('
',{className:'progressBar'}) .appendTo(elements.container); elements.elapsed = $('
',{className:'elapsed'}) .appendTo(elements.progress); elements.progress.click(function(e){ // When a click occurs on the progress bar, seek to the // appropriate moment of the video. var ratio = (e.pageX-elements.progress.offset().left)/elements.progress.outerWidth(); elements.elapsed.width(ratio*100+'%'); elements.player.seekTo(Math.round(data.duration*ratio), true); return false; }); }

In the second part of the code, we use the SWFObject plugin to generate the embed code of  the youtube chromeless player. Notice that the id of the video is passed as a flashvar so the player can load it directly. The safeID variable (a JavaScript safe version of the videoid) becomes the value of the id parameter of the to-be generated object element. This way we can later fetch the DOM element by running document.getElementById(‘video_’+settings.safeID) and get access to the methods which control the youtube player (play, pause etc).

youTubeEmbed-jquery-1.0.js – Part 3

var initialized = false;

// Creating a global event listening function for the video
// (required by YouTube's player API):

window['eventListener_'+settings.safeID] = function(status){

	var interval;

	if(status==-1)	// video is loaded
	{
		if(!initialized)
		{
			// Listen for a click on the control button:

			elements.control.click(function(){
				if(!elements.container.hasClass('playing')){

					// If the video is not currently playing, start it:

					elements.control.removeClass('play replay').addClass('pause');
					elements.container.addClass('playing');
					elements.player.playVideo();

					if(settings.progressBar){
						interval = window.setInterval(function(){
							elements.elapsed.width(
					((elements.player.getCurrentTime()/data.duration)*100)+'%'
							);
						},1000);
					}

				} else {

					// If the video is currently playing, pause it:

					elements.control.removeClass('pause').addClass('play');
					elements.container.removeClass('playing');
					elements.player.pauseVideo();

					if(settings.progressBar){
						window.clearInterval(interval);
					}
				}
			});

			initialized = true;
		}
		else{
			// This will happen if the user has clicked on the
			// YouTube logo and has been redirected to youtube.com

			if(elements.container.hasClass('playing'))
			{
				elements.control.click();
			}
		}
	}

In order to be able to control the video player, we need to be notified when certain events (like playback stopped, video ready etc) occur. Normally, this would mean that we need to pass a callback function, which is executed by the player every time such an event happens.

Unfortunately, flash can only execute functions if they are defined in the global scope and cannot see the functions which are defined inside the plugin. However, by creating functions with unique names (with the safeID) and explicitly adding them to the window object we can make this happen. If it weren’t for this little trick, it would be impossible for the plugin to work.

youTubeEmbed-jquery-1.0.js – Part 4

				if(status==0){ // video has ended
					elements.control.removeClass('pause').addClass('replay');
					elements.container.removeClass('playing');
				}
			}

			// This global function is called when the player is loaded.
			// It is shared by all the videos on the page:

			if(!window.onYouTubePlayerReady)
			{
				window.onYouTubePlayerReady = function(playerID){
					document.getElementById('video_'+playerID).addEventListener('onStateChange','eventListener_'+playerID);
				}
			}
		},'jsonp');

		return elements.originalDIV;
	}

})(jQuery);

The event listening function we created in the previous section of the code, is attached to the player with the addEventListener method. It is called every time when a “stateChange” occurs (playback start, playback pause, end of playback etc). A numeric code is passed to the event listening function as a parameter, corresponding to the event.

Now lets take a look at how our plugin is used.

script.js

$(document).ready(function(){

	$('#player').youTubeEmbed('http://www.youtube.com/watch?v=u1zgFlCw8Aw');

	/*
		//You can alternatively pass an object:

		$('#player').youTubeEmbed({
			video			: 'http://www.youtube.com/watch?v=u1zgFlCw8Aw',
			width			: 600, 		// Height is calculated automatically
			progressBar	: false		// Hide the progress bar
		});

	*/

});

You just need to call the youTubeEmbed() method and pass it either a string or a configuration object. If a string is passed, it is assumed to be the URL of a YouTube video. If you are passing an object make sure that you are passing the video property with a correct video URL.

Video Playing with a Progress Bar

Video Playing with a Progress Bar

Step 3 – CSS

Finally we are left with applying a few CSS styles to the player. They will change the design of the player controls and define the way they are positioned in the player window.

youTubeEmbed-jquery-1.0.css

.flashContainer{

	/*	Setting the container to relative positioning
		so we can center the control div */

	position:relative;
	overflow:hidden;
}

.progressBar{
	display:none;
	position:absolute;
	width:auto;
	height:8px;
	left:20px;
	right:105px;
	bottom:20px;
	background-color:#141414;
	overflow:hidden;
	cursor:pointer;

	/* A light CSS3 bottom highlight */

	-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.3);
	-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.3);
	box-shadow:0 1px 0 rgba(255, 255, 255, 0.3);
}

.progressBar .elapsed{
	position:absolute;
	width:0;
	height:100%;
	background-color:#1fa2f6;
	border-right:1px solid #49AFF0;
}

.controlDiv{
	/* Centering the control div */
	position:absolute;
	width:120px;
	height:120px;
	cursor:pointer;
	top:50%;
	left:50%;
	margin:-60px 0 0 -60px;
}

.controlDiv.play{
	background:url('img/play.png') no-repeat center center;
}

.controlDiv.replay{
	background:url('img/replay.png') no-repeat center center;
}

.controlDiv.pause{
	background:url('img/pause.png') no-repeat -99999px;
}

.flashContainer:hover .controlDiv.pause{
	background-position:center center;
}

/* Only show the progress bar when the video is playing */

.flashContainer.playing:hover .progressBar{
	display:block;
}

To customize the look of the player you just need to change the color values above. Also you can edit the png files with the play/pause buttons. Clearly this is much easier than modifying the looks of the default youtube player. It also strips all of the unnecessary chrome and leaves you with what matters most – your video.

With this our Custom YouTube Player plugin is complete!

Did you like this tutorial? Share your thoughts in the comment section below.

Tutorialzine/tutorials/~4/J82EX5txNss" height="1" width="1" />


Filed under: ASP,Buttons,CSS,Comment,Design,Information,JavaScript,Script,Tech,Tools,Tutorial,Upload,jQuery

Trackback Uri