<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Nettuts+</title>
	
	<link>http://net.tutsplus.com</link>
	<description>Web Development &amp; Design Tutorials</description>
	<pubDate>Thu, 09 Jul 2009 16:33:27 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<image><link>http://nettuts.com</link><url>http://envato.s3.amazonaws.com/rss_images/nettuts.jpg</url><title>NETTUTS</title></image><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/nettuts" type="application/rss+xml" /><feedburner:emailServiceId>nettuts</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>Kohana: The Swift PHP Framework</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/xQvIVotk2rM/</link>
		<comments>http://net.tutsplus.com/tutorials/php/kohana-the-swift-php-framework/#comments</comments>
		<pubDate>Thu, 09 Jul 2009 16:23:17 +0000</pubDate>
		<dc:creator>Cristian</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[framework]]></category>

		<category><![CDATA[kohama php framework]]></category>

		<category><![CDATA[kohana]]></category>

		<category><![CDATA[kohana framework]]></category>

		<category><![CDATA[php framework]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5750</guid>
		<description><![CDATA[<img src="http://nettuts.s3.amazonaws.com/376_kohana/200x200.jpg" alt="Kohana: The Swift PHP Framework" />]]></description>
			<content:encoded><![CDATA[<p>Kohana is a PHP 5 framework that uses the Model View Controller (MVC) architectural pattern. There are several reasons why you should choose Kohana but the main ones are security, weightlessness and simplicity. In this tutorial, I&#8217;ll introduce its main features, and, with a simple demonstration, I&#8217;ll show you how much time Kohana can potentially save you.</p>
<p><span id="more-5750"></span></p>
<h3>Step 1: What is Kohana?</h3>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/376_kohana/logo.png" border="0" /></div>
<p>Kohana is a PHP5 framework that uses the Model View Controller architectural pattern. MVC keeps application logic<br />
separate from the presentation. This allows us to create cleaner code and save time for bug searching.<br />
In unfamiliar with this pattern:</p>
<ul>
<li>A <b>Model</b> represents data on which the application operates. Usually a database.</li>
<li>A <b>View</b> contains presentation code such as HTML, CSS and JavaScript.</li>
<li>A <b>Controller</b> interprets input from the user and sends to the model and/or view.</li>
</ul>
<p>Kohana was originally a fork of <a href="http://www.codeigniter.com">CodeIgniter</a> (CI), which is an open-source product from EllisLab. There are many similarities between CI and Kohana, but all of the code is either new or completely rewritten. As you can read on the official <a href="http://www.kohanaphp.com">Kohana</a> web site, the main features are:</p>
<ul>
<li>Highly secure</li>
<li>Extremely lightweight</li>
<li>Short learning curve</li>
<li>Uses the MVC pattern</li>
<li>100% UTF-8 compatible</li>
<li>Loosely coupled architecture</li>
<li>Extremely easy to extend</li>
</ul>
<h3>Step 2: Downloading Kohana</h3>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/376_kohana/download.jpg" border="0" /></div>
<p>Let&#8217;s get started. Visit Kohana&#8217;s official web site <a title="http://kohanaphp.com/" href="http://kohanaphp.com/" target="_new">http://kohanaphp.com</a> and click on the green box in the right corner to download the latest version. All Kohana libraries, helpers, and views are included in the default download package, but you may select extra modules, vendor tools, and languages if you want. For the purpose of this tutorial, the default package can be enough. Click on &#8220;Download Kohana!&#8221; to begin the download.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/376_kohana/download_page.jpg" border="0" /></div>
<h3>Step 3: Installing Kohana</h3>
<p>Once you&#8217;ve finished downloading it:</p>
<ol>
<li>Unzip</li>
<li>Rename the &#8220;Kohana_vx.x.x&#8221; folder to &#8220;kohana&#8221; and upload it to your web server document root</li>
<li>Edit the global configuration file <b>application/config/config.php</b> as follows</li>
<pre name="code" class="php">$config['site_domain'] = 'localhost/kohana';</pre>
<li>If you are using a unix-like system, the installation&#8217;s subdirs may have lost their permissions during zip extraction. Chmod them all to 755 by running <b>find . -type d -exec chmod 755 {} \;</b> from the root of your Kohana installation.</li>
<li>Make sure the <b>application/logs</b> and <b>application/cache</b> directories are writeable. Chmod to 666.</li>
<li>Now, point your browser to http://localhost/kohana/. Automatically, the framework will call the install.php script and check for your server requirements.</li>
</ol>
<p>Kohana will run in nearly any environment with minimal configuration. There are a few minimum server requirements:</p>
<ul>
<li>Server with Unicode support</li>
<li>PHP version &gt;= 5.2.3</li>
<li>An HTTP server. I suggest you use <a title="http://www.apachefriends.org/" href="http://www.apachefriends.org/" target="_new">XAMPP</a>. XAMPP is an easy all-in-one tool to install MySQL, PHP and Perl.</li>
<li>Database (MsSQL, MySQL, MySQLi, PostgreSQL, PDOSqlite)</li>
</ul>
<p>There are also some required extensions. </p>
<ul>
<li><b>PCRE</b></li>
<li><b>iconv</b></li>
<li><b>mcrypt</b></li>
<li><b>SPL</b></li>
</ul>
<p>If your installation completes successfully, you will be redirected to this test page:</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/376_kohana/install.jpg" border="0" /></div>
<p>If any of the tests fail, you must correct them before moving forward.</p>
<p>If all tests have passed, go to the Kohana directory and remove or rename the install.php script. Refresh, and you will see a welcome page like this:</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/376_kohana/welcome.jpg" border="0" /></div>
<h3>Step 4: Configuring Kohana</h3>
<p>Kohana is ready to go. No other configuration is needed. This framework is amazing. Isn&#8217;t it? Let&#8217;s review some code. Follow me.</p>
<h3>Step 5: Your first Kohana Project</h3>
<p>Canonical programming tutorials start with the &#8220;Hello world&#8221; example. I think, instead, that a simple application can give you a clear idea how the framework works. So, we will build a CD collection manager &#8212; just for a fun demonstration. Before we start coding, a brief introduction to Kohana file system is required.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/376_kohana/tree.jpg" border="0" /></div>
<p>Our application will be placed in the <b>application</b> folder. In this folder there are several sub folders but we need the following for our project:</p>
<ul>
<li><b>config</b> folder hosts all the configuration files coded as simple static arrays.</li>
<li><b>controllers</b> folder hosts our custom controllers class</li>
<li><b>models</b> folder hosts our custom models class</li>
<li><b>views</b> folder hosts our custom files written in HTML (or any markup language or script needed to display data and interface controls to the user)</li>
</ul>
<p>The remaining sub folders are not required for this tutorial, so I invite you to learn more on the Kohana web site.</p>
<p>The <b>system</b> folder host the Kohana core and the Kohana tools like libraries, helpers and predefined configuration files. In this project we will use some libraries and some helpers - good tools to speed up your work.</p>
<p>The <b>assets</b> folder is not a predefined Kohana folder. I have created it for media files like CSS, JS, and images. I&#8217;ll show you how to include these files in the project.</p>
<p>The <b>modules</b> folder is the place to put reusable collections of related files that together add a particular functionality to an application. The authentication module, provided by the Kohana team, is an example of module.</p>
<p>This is a very brief introduction to the Kohana file system, but it&#8217;s enough for the purposes of this tutorial. I don&#8217;t want to bore you more with theory.</p>
<h3>Step 6: Project Database</h3>
<p>I have chosen MySQL as my DBMS, but remember that Kohana also supports MsSQL, MySQLi, PostgreSQL, PDOSqlite. Create a database called &#8220;cd_collection&#8221; or choose the name you prefer, and run the following SQL through phpMyAdmin or any tool to handle the administration of MySQL.</p>
<pre name="code" class="php">
CREATE TABLE `albums` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(50) collate utf8_bin NOT NULL,
  `author` varchar(50) collate utf8_bin NOT NULL,
  `genre_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `genre_id` (`genre_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=19 ;

INSERT INTO `albums` (`id`, `name`, `author`, `genre_id`) VALUES
(2, 'Lines, Vines And Trying Times', 'Jonas Brothers', 16),
(3, 'The E.N.D.', 'The Black Eyed Peas', 16),
(4, 'Relapse', 'Eminem', 18),
(5, 'Monuments And Melodies', 'Incubus', 1),
(6, 'Thriller', 'Michael Jackson', 16),
(7, 'Back in Black', 'AC/DC', 4),
(8, 'The Dark Side of the Moon', 'Pink Floyd', 4),
(9, 'Bat out of Hell', 'Meat Loaf', 4),
(10, 'Backstreet Boys', 'Millennium', 16),
(11, 'Rumours', 'Fleetwood Mac', 4),
(12, 'Come on Over', 'Shania Twain', 16),
(13, 'Led Zeppelin IV', 'Led Zeppelin', 4),
(14, 'Jagged Little Pill', 'Alanis Morissette', 4),
(15, 'Sgt. Pepper''s Lonely Hearts Club Band', 'The Beatles', 16),
(16, 'Falling into You', 'C√©line Dion', 16),
(17, 'Music Box', 'Mariah Carey', 16),
(18, 'Born in the U.S.A.', 'Bruce Springsteen', 4);

CREATE TABLE `genres` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(50) collate utf8_bin NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=22 ;

INSERT INTO `genres` (`id`, `name`) VALUES
(1, 'Alternative Rock'),
(2, 'Blues'),
(3, 'Classical'),
(4, 'Rock'),
(5, 'Country'),
(6, 'Dance'),
(7, 'Folk'),
(8, 'Metal'),
(9, 'Hawaiian'),
(10, 'Imports'),
(11, 'Indie Music'),
(12, 'Jazz'),
(13, 'Latin'),
(14, 'New Age'),
(15, 'Opera'),
(16, 'Pop'),
(17, 'Soul'),
(18, 'Rap'),
(20, 'Soundtracks'),
(21, 'World Music');

ALTER TABLE `albums`
  ADD CONSTRAINT `genre_inter_relational_constraint` FOREIGN KEY (`genre_id`) REFERENCES `genres` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
</pre>
<p>As you can see, the SQL creates two tables, albums and genres, and populates them with some data. The last SQL statement adds a constraint for the foreign key &#8220;genre_id&#8221;.</p>
<p>The database structure is very simple and doesn&#8217;t need much explanation. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/376_kohana/er.jpg" border="0" /></div>
<p>Now, you have to tell Kohana where your database is located and how to access it. Edit the global configuration file <b>system/config/database.php</b> as follows</p>
<pre name="code" class="php">
$config['default'] = array
(
	'benchmark'     =&gt; TRUE,
	'persistent'    =&gt; FALSE,
	'connection'    =&gt; array
	(
		'type'     =&gt; 'mysql',
		'user'     =&gt; 'root',
		'pass'     =&gt; 'root',
		'host'     =&gt; 'localhost',
		'port'     =&gt; FALSE,
		'socket'   =&gt; FALSE,
		'database' =&gt; 'cd_collection'
	),
	'character_set' =&gt; 'utf8',
	'table_prefix'  =&gt; '',
	'object'        =&gt; TRUE,
	'cache'         =&gt; FALSE,
	'escape'        =&gt; TRUE
);
</pre>
<p>This code tells Kohana to connect to a MySQL database called &#8220;cd_collection&#8221; on localhost with the username &#8220;root&#8221; and the password &#8220;root&#8221;. You have to change these settings according to your database server configuration.</p>
<h3>Step 7: Create the Controller</h3>
<p>Let&#8217;s now create our first controller. Remember these conventions. </p>
<ul>
<li>controller filename must be lowercase, e.g. album.php</li>
<li>controller class must map to filename and capitalized, and must be appended with _Controller, e.g. Album_Controller</li>
<li>must have the Controller class as (grand)parent</li>
</ul>
<p>
	Also, remember how Kohana structures its URLs and how you can call a controller method; e.g http://hostname/kohana_directory/index.php/controller/function.
</p>
<p>Let&#8217;s take a look at this simple controller. </p>
<pre name="code" class="php">
&lt;?php defined('SYSPATH') OR die('No direct access allowed.');

class Album_Controller extends Controller
{
	public function __construct()
 	{
		parent::__construct();
	}

	public function index()
 	{
 	  	echo "My first controller";
	}
}
</pre>
<p>PHP5 OOP is a prerequisite. So if you aren&#8217;t well-versed, you can learn more <a href="http://www.php.net/manual/en/language.oop5.php">here</a>.</p>
<p>
	The constructor function, called  __construct, initializes the class and calls the parent constructor.<br />
	The index function is the default function, so it will be called if we call the controller without<br />
	specifying any function (e.g. http://localhost/index.php/kohana/album. After the name controller<br />
	there isn&#8217;t any function, the default index function will be called.)
 </p>
<p>
 	Given these basic rules, let&#8217;s focus on our application. The album controller implements all the actions for<br />
	the albums collection management. This controller allows us to create a new album, to show the albums stored in our database,<br />
	to update an album, and to delete an album.
	</p>
<p>
	So, let&#8217;s change the class as follows.
 </p>
<p>Create a file called <b>album.php</b> in <b>application/controllers/</b> and paste the following.</p>
<pre name="code" class="php">
&lt;?php defined('SYSPATH') OR die('No direct access allowed.');

class Album_Controller extends Controller
{
	 private $album_model;
	 private $genre_model;

	 private $list_view;
	 private $create_view;
	 private $update_view;

	public function __construct()
 	{
		parent::__construct();
		$this-&gt;album_model   = new Album_Model;
		$this-&gt;genre_model  	= new Genre_Model;
	  	$this-&gt;list_view   	= new View('list');
	  	$this-&gt;update_view  	= new View('update');
	  	$this-&gt;create_view  	= new View('create');
	}

 	public function index()
 	{
  		$this-&gt;show_albums_list();
 	}

	private function show_albums_list()
	{
		$albums_list = $this-&gt;album_model-&gt;get_list();
		$this-&gt;list_view-&gt;set('albums_list',$albums_list);
		$this-&gt;list_view-&gt;render(TRUE);
	}

 	public function show_create_editor()
 	{
 		$this-&gt;create_view-&gt;set('genres_list',$this-&gt;get_genres_list());
  		$this-&gt;create_view-&gt;render(TRUE);
 	}

 	public function show_update_editor($id)
 	{
		$album_data = $this-&gt;album_model-&gt;read($id);
		$this-&gt;update_view-&gt;set('album_id',$album_data[0]-&gt;id);
		$this-&gt;update_view-&gt;set('name',$album_data[0]-&gt;name);
		$this-&gt;update_view-&gt;set('author',$album_data[0]-&gt;author);
		$this-&gt;update_view-&gt;set('genre_id',$album_data[0]-&gt;genre_id);
		$this-&gt;update_view-&gt;set('genres_list',$this-&gt;get_genres_list());
		$this-&gt;update_view-&gt;render(TRUE);
 	}

 	public function create()
 	{
		$album_data=array(
		'name'    	=&gt; $this-&gt;input-&gt;post('name'),
		'author'  	=&gt; $this-&gt;input-&gt;post('author'),
		'genre_id'  =&gt; $this-&gt;input-&gt;post('genre_id')
		);
		$this-&gt;album_model-&gt;create($album_data);
		url::redirect('album');
 	}

	public function update()
	{
		$album_data = array(
			'name'    	=&gt; $this-&gt;input-&gt;post('name'),
			'author'  	=&gt; $this-&gt;input-&gt;post('author'),
			'genre_id'  =&gt; $this-&gt;input-&gt;post('genre_id')
		);
		$this-&gt;album_model-&gt;update($this-&gt;input-&gt;post('album_id'),$album_data);
  		url::redirect('album');
 	}

  	public function delete($id)
 	{
		$this-&gt;album_model-&gt;delete($id);
		url::redirect('album');
 	}

	private function get_genres_list()
	{
		$db_genres_list  = $this-&gt;genre_model-&gt;get_list();
		$genres_list  = array();

		if(sizeof($db_genres_list) &gt;= 1)
		{
			foreach($db_genres_list as $item)
			{
				$genres_list[$item-&gt;id] = $item-&gt;name;
			}
		}
		return $genres_list;
 	}
}
</pre>
<p>
Let me explain what this code does. </p>
<p>
<b>Five members variables are declared at the top of the class:</b></p>
<pre name="code" class="php">
private $album_model;
private $genre_model;

private $list_view;
private $create_view;
 private $update_view;
</pre>
<p>
These members are private because I want to limit visibility only to this class.
</p>
<p><b>In the construct method the model and view objects are created using the five members:</b></p>
<pre name="code" class="php">
$this-&gt;album_model   = new Album_Model;
$this-&gt;genre_model  	= new Genre_Model;
$this-&gt;list_view   	= new View('list');
$this-&gt;update_view  	= new View('update');
$this-&gt;create_view  	= new View('create');
</pre>
<p>
To create a model object use this syntax:
</p>
<pre name="code" class="php">
$obj_name = new Name_Model;
</pre>
<p>
To create a view object, use this syntax: </p>
<pre name="code" class="php">
$obj_name = new View('view_filename_without_extension');
</pre>
<p>
Now there are two objects to access the album and genre model, and three objects to access the views needed to render the presentation.
</p>
<p><b>The index method call the show_albums_list method that lists all albums stored in the database.</b></p>
<pre name="code" class="php">
$albums_list = $this-&gt;album_model-&gt;get_list();
$this-&gt;list_view-&gt;set('albums_list',$albums_list);
$this-&gt;list_view-&gt;render(TRUE);
</pre>
<p>
In this method you can see how the model and view object are used to access relative methods. &#8220;get_list&#8221; is a model method (we will see it later) that returns all the albums stored in the database. The result is saved in the &#8220;$album_list&#8221; array. To pass the result array from the controller to the view, the &#8220;set&#8221; method is called on the view object. This method requires two parameters: a new empty variable (album_list) to contain data of an existing variable ($album_list). Now the new variable &#8220;album_list&#8221; contains the $album_list array (we will see later how to show the content in the view). The method &#8220;render&#8221;, with the TRUE parameter, is necessary to output data to the browser.
</p>
<p><b>The show_create_editor method shows the user interface to insert a new album.</b></p>
<pre name="code" class="php">
$this-&gt;create_view-&gt;set('genres_list',$this-&gt;get_genres_list());
$this-&gt;create_view-&gt;render(TRUE);
</pre>
<p>
The list of the genres is passed to the view.
</p>
<p><b>The show_update_editor method shows the user interface to update an existing album.</b></p>
<pre name="code" class="php">
$album_data = $this-&gt;album_model-&gt;read($id);
$this-&gt;update_view-&gt;set('album_id',$album_data[0]-&gt;id);
$this-&gt;update_view-&gt;set('name',$album_data[0]-&gt;name);
$this-&gt;update_view-&gt;set('author',$album_data[0]-&gt;author);
$this-&gt;update_view-&gt;set('genre_id',$album_data[0]-&gt;genre_id);
$this-&gt;update_view-&gt;set('genres_list',$this-&gt;get_genres_list());
$this-&gt;update_view-&gt;render(TRUE);
</pre>
<p>
&#8220;read&#8221; is a model method (we will see it later) that returns data ($album_data) of the album with an id equal to $id. Then, every single element of the returned data album is passed to the view.
</p>
<p><b>The create method receives data, for a new album, from the view and data are stored in the database.</b></p>
<pre name="code" class="php">
		$album_data=array(
		'name'    	=&gt; $this-&gt;input-&gt;post('name'),
		'author'  	=&gt; $this-&gt;input-&gt;post('author'),
		'genre_id'  =&gt; $this-&gt;input-&gt;post('genre_id')
		);
		$this-&gt;album_model-&gt;create($album_data);
		url::redirect('album');
</pre>
<p>
$album_data is an array that contains the POST data from the view. To save the album, the array is passed to the create model method. The last line is a call to a helper method. Helpers are simply functions that assist you with development. The helper classes are automatically loaded by the framework. Helpers are declared as static methods of a class, so there is no need to instantiate the class. In this case the method &#8220;redirect&#8221; of the helper &#8220;url&#8221; is called and tells Kohana to redirect the browser to the album controller. This avoids a new insert (for example pressing F5).
</p>
<blockquote><p>&#8220;Helpers are simply functions that assist you with development.&#8221;</p>
</blockquote>
<p><b>The update and delete methods work in the same manner as the create method above.</b></p>
<p><b>The last method get_genres_list gets the genres list from the model ($db_genres_list) and builds a new array ($genres_list) for the select box in the views. </b></p>
<pre name="code" class="php">
		$db_genres_list  = $this-&gt;genre_model-&gt;get_list();
		$genres_list  = array();

		if(sizeof($db_genres_list) &gt;= 1)
		{
			foreach($db_genres_list as $item)
			{
				$genres_list[$item-&gt;id] = $item-&gt;name;
			}
		}
		return $genres_list;
</pre>
<h3>Step 8: Create Project Model</h3>
<p>Let&#8217;s now create models for our web application. Remember these conventions. </p>
<ul>
<li>model filename must be lowercase, e.g. album.php</li>
<li>model class must map to filename and be capitalized, and must be appended with _Model, e.g. Album_Model</li>
<li>must have the Model class as (grand)parent</li>
</ul>
<p>Here is the album model code. Create a file called <b>album.php</b> in <b>application/models/</b> and paste the code below on it. </p>
<pre name="code" class="php">
&lt;?php defined('SYSPATH') OR die('No direct access allowed.');

class Album_Model extends Model
{
 	private $album_table;
 	private $genre_table; 

  	public function __construct()
    	{
      		parent::__construct();
  		$this-&gt;album_table = 'albums';
		$this-&gt;genre_table = 'genres';
  	}

  	public function read($id)
  	{
		$this-&gt;db-&gt;where('id', $id);
		$query = $this-&gt;db-&gt;get($this-&gt;album_table);
  		return $query-&gt;result_array();
 	}

	public function delete($id)
  	{
		$this-&gt;db-&gt;delete($this-&gt;album_table, array('id' =&gt; $id));
  	}

  	public function update($id,$data)
  	{
		$this-&gt;db-&gt;update($this-&gt;album_table, $data, array('id' =&gt; $id));
  	}

	public function create($data)
  	{
   		$this-&gt;db-&gt;insert($this-&gt;album_table, $data);
  	}

	public function get_list()
 	{
  		$this-&gt;db-&gt;select('albums.id as id,albums.name as name,albums.author as author, genres.name as genre');
  		$this-&gt;db-&gt;from($this-&gt;album_table);
  		$this-&gt;db-&gt;join($this-&gt;genre_table,'genres.id','albums.genre_id');
  		$query = $this-&gt;db-&gt;get();
  		return $query-&gt;result_array();
	}
}
</pre>
<p>All the methods in the models make use of the Query builder syntax. This Kohana tool speeds up database development times and simplify the queries creation.</p>
<p>
	Two members variables are declared at the top of the class:</p>
<pre name="code" class="php">
			private $album_table;
			private $genre_table;
	</pre>
<p>These members are private because I want to limit the visibility only to this class. They are the containers for the database tables names.
	</p>
<p>The first line in the constructor method loads the Kohana database library into $this-&gt;db. In the second and third lines the two class members are initialized. </p>
<pre name="code" class="php">
parent::__construct();
$this-&gt;album_table = 'albums';
$this-&gt;genre_table = 'genres';
</pre>
<p>The query in the read method retrieves album records that have a certain identifier (&#8221;$id&#8221;). </p>
<pre name="code" class="php">
			$this-&gt;db-&gt;where('id', $id);
		 	$query = $this-&gt;db-&gt;get($this-&gt;album_table);
	  	 	return $query-&gt;result_array();
	</pre>
<p>The query in the delete method deletes the albums table row that have a certain identifier (&#8221;$id&#8221;). </p>
<pre name="code" class="php">
$this-&gt;db-&gt;delete($this-&gt;album_table, array('id' =&gt; $id));
	</pre>
<p>The query in the update method updates the albums table row that has a certain identifier (&#8221;$id&#8221;) with new values from the &#8220;$data&#8221; array.</b></p>
<pre name="code" class="php">
$this-&gt;db-&gt;update($this-&gt;album_table, $data, array('id' =&gt; $id));
	</pre>
<p>
	The &#8220;$data&#8221; array must contain record names as keys of the array, and value as values of the array. The &#8220;$data&#8221; array must have this form:
</p>
<pre name="code" class="php">
$data = array(
	'name' 			=&gt; 	'album_name',
	'author'		=&gt;	'author_name',
	'genre_id'		=&gt;	'genre_id'
	);
	</pre>
<p>The query in the create method inserts a new record with values of the &#8220;$data&#8221; array.</p>
<pre name="code" class="php">
$this-&gt;db-&gt;insert($this-&gt;album_table, $data);
	</pre>
<p>
	The &#8220;$data&#8221; array must have this form:
</p>
<pre name="code" class="php">
$data = array(
	'id'			=&gt;	'album_id',
	'name' 			=&gt; 	'album_name',
	'author'		=&gt;	'author_name',
	'genre_id'		=&gt;	'genre_id'
);
	</pre>
<p>The query in the get_list method retrieves all the albums rows.	</p>
<pre name="code" class="php">
		$this-&gt;db-&gt;select('albums.id as id,albums.name as name,albums.author as author, genres.name as genre');
		$this-&gt;db-&gt;from($this-&gt;album_table);
		$this-&gt;db-&gt;join($this-&gt;genre_table,'genres.id','albums.genre_id');
		$query = $this-&gt;db-&gt;get();
		return $query-&gt;result_array();
	</pre>
<p>Now, the genre model. Create a file called <b>genre.php</b> in <b>application/models/</b> and paste the code below it: </p>
<pre name="code" class="php">
	&lt;?php defined('SYSPATH') OR die('No direct access allowed.');

	class Genre_Model extends Model
	{
		private $genre_table;

		function __construct()
		{
			parent::__construct();
			$this-&gt;genre_table = 'genres';
		}

		function get_list()
		{
			$query = $this-&gt;db-&gt;get($this-&gt;genre_table);
			return  $query-&gt;result_array();
		}
	}
	</pre>
<p>
		This model is very simple so I&#8217;ll waste no further time to comment upon it. The Models and the controller are ready to go. Let&#8217;s now work on the Views.
	</p>
<h3>Step 9: Create the Project View</h3>
<p>Views are files that contain the presentation layer for your application. The purpose is to keep this information separate from your application logic for easy reusability and cleaner code. For this project, three views are required: a view to list the album collection, a view to create a new album, and a view to edit an existing album.</p>
<p>Create a file called <b>list.php</b> in <b>application/views/</b> and paste the following code in: </p>
<pre name="code" class="php">
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;?php
	echo html::stylesheet(array
		(
		 'assets/css/style'
		),
		array
		(
		 'screen'
		), FALSE);
?>
		&lt;title&gt;CD COLLECTION&lt;/title&gt;
		&lt;/head&gt;
		&lt;body&gt;
		&lt;?php
				echo html::image('assets/images/add.png');
				echo html::anchor('album/show_create_editor', 'Add new album');
		?&gt;
		&lt;table class="list" cellspacing="0"&gt;
		&lt;tr&gt;
			&lt;td colspan="5" class="list_title"&gt;CD Collection&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td class="headers"&gt;Album name&lt;/td&gt;
			&lt;td class="headers"&gt;Author&lt;/td&gt;
			&lt;td colspan='3' class="headers"&gt;Genre&lt;/td&gt;

		&lt;/tr&gt;
		&lt;?php
			foreach($albums_list as $item)
			{
				echo "&lt;tr&gt;";
				echo "&lt;td class='item'&gt;".$item-&gt;name."&lt;/td&gt;";
				echo "&lt;td class='item'&gt;".$item-&gt;author."&lt;/td&gt;";
				echo "&lt;td class='item'&gt;".$item-&gt;genre."&lt;/td&gt;";
				echo "&lt;td class='item'&gt;".html::anchor('album/delete/'.$item-&gt;id,html::image('assets/images/delete.png'))."&lt;/td&gt;";
				echo "&lt;td class='item'&gt;".html::anchor('album/show_update_editor/'.$item-&gt;id,html::image('assets/images/edit.png'))."&lt;/td&gt;";
				echo "&lt;/tr&gt;";
			}
		?&gt;
		&lt;/table&gt;
		&lt;/body&gt;
		&lt;/html&gt;
	</pre>
<p>This view shows an html page containing a list of all albums. This list has been created using foreach loop that prints the information in an html table. For each album row, there are two images: a &#8220;red cross&#8221; and a &#8220;pocketbook&#8221;. They link respectively the controller delete method and the update method. Both pass the album id to the album controller using a get request. Above the list there is a button to create new albums. In this code we also make use of an html helper provided by Kohana that speeds up operations to write html pages.</p>
<p>Let&#8217;s now create a file called <b>create.php</b> in <b>application/views/</b>. </p>
<pre name="code" class="php">
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;?php
	echo html::stylesheet(array
	(
	    'assets/css/style'
	),
	array
	(
	    'screen'
	), FALSE);
?&gt;
&lt;title&gt;CD COLLECTION&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;?php echo form::open('album/create'); ?&gt;
&lt;table class='editor'&gt;
&lt;tr&gt;
	&lt;td colspan='2' class='editor_title'&gt;Create new album&lt;/td&gt;
&lt;/tr&gt;
&lt;?php
	echo "&lt;tr&gt;";
	echo "&lt;td&gt;".form::label('name', 'Name: ')."&lt;/td&gt;";
	echo "&lt;td&gt;".form::input('name', '')."&lt;/td&gt;";
	echo "&lt;/tr&gt;";

	echo "&lt;tr&gt;";
	echo "&lt;td&gt;".form::label('author', 'Author: ')."&lt;/td&gt;";
	echo "&lt;td&gt;".form::input('author', '')."&lt;/td&gt;";
	echo "&lt;tr/&gt;";

	echo "&lt;tr&gt;";
	echo "&lt;td&gt;".form::label('genre', 'Genre: ')."&lt;/td&gt;";
	echo "&lt;td&gt;".form::dropdown('genre_id',$genres_list)."&lt;/td&gt;";
	echo "&lt;tr/&gt;";

	echo "&lt;tr&gt;";
	echo "&lt;td colspan='2' align='left'&gt;".form::submit('submit', 'Create album')."&lt;/td&gt;";
	echo "&lt;/tr&gt;";
?&gt;
&lt;/table&gt;
&lt;?php echo form::close(); ?&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
</p>
<p>The last but not the least is the update view. Let&#8217;s create a file called <b>update.php</b> in <b>application/views/</b>.</p>
<pre name="code" class="php">
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;?php
	echo html::stylesheet(array
	(
	    'assets/css/style'
	),
	array
	(
	    'screen'
	), FALSE);
?&gt;
&lt;title&gt;CD COLLECTION&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;?php echo form::open('album/update'); ?&gt;
&lt;table class='editor'&gt;
&lt;tr&gt;
	&lt;td colspan='2' class='editor_title'&gt;Update album&lt;/td&gt;
&lt;/tr&gt;
&lt;?php
	echo "&lt;tr&gt;";
	echo "&lt;td&gt;".form::label('name', 'Name: ')."&lt;/td&gt;";
	echo "&lt;td&gt;".form::input('name', $name)."&lt;/td&gt;";
	echo "&lt;/tr&gt;";

	echo "&lt;tr&gt;";
	echo "&lt;td&gt;".form::label('author', 'Author: ')."&lt;/td&gt;";
	echo "&lt;td&gt;".form::input('author', $author)."&lt;/td&gt;";
	echo "&lt;tr/&gt;";

	echo "&lt;tr&gt;";
	echo "&lt;td&gt;".form::label('genre', 'Genre: ')."&lt;/td&gt;";
	echo "&lt;td&gt;".form::dropdown('genre_id',$genres_list, $genre_id)."&lt;/td&gt;";
	echo "&lt;tr/&gt;";

	echo "&lt;tr&gt;";
	echo "&lt;td colspan='2' align='left'&gt;".form::submit('submit', 'Update album')."&lt;/td&gt;";
	echo "&lt;/tr&gt;";

?&gt;
&lt;/table&gt;
&lt;?php
	echo form::hidden('album_id',$album_id);
	echo form::close();
?&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>
	The first one is a simple editor that enables the user to insert information about a new album.<br />
	The fields like author and name will be inserted using an html input and genre using a<br />
	combo box. Once the user clicks on the create button, all information is passed,<br />
	as a POST request, to the create/update method in the album controller. When the controller receives these posted<br />
	variables, it calls the model that inserts a new album into the database. The forms, in both views, makes use of Kohana form helper.
</p>
<p>
	To give a bit of style to our application, create the <b>assets</b> folder in the Kohana root at the same level of the application folder. Now, open it and create two new folders: <b>css</b> and <b>images</b>.
</p>
<p>In the <b>css</b> folder create a new file called <b>style.css</b> and paste this: </p>
<pre name="code" class="css">
a {
	font-family: Verdana, Geneva, Arial, Helvetica, sans-serif ;
	font-weight: normal;
	font-size: 12px;
	color: #00F;
	vertical-align:text-top;
}

img {
	border: 0;
}

label {
	font-family: Verdana, Geneva, Arial, Helvetica, sans-serif ;
	font-weight: normal;
	font-size: 12px;
}

input {
	border: 1px solid #000;
}

select {
	width:185px;
}

table.editor
{
	text-align: center;
	font-family: Verdana, Geneva, Arial, Helvetica, sans-serif ;
	font-weight: normal;
	font-size: 11px;
	color: #fff;
	width: 280px;
	background-color: #666;
	border: 0px;
	border-collapse: collapse;
	border-spacing: 0px;
}

table.editor td.editor_title
{
	background-color: #666;
	color: #fff;
	padding: 4px;
	text-align: left;
	font-weight: bold;
	font-size: 16px;
} 

table.editor td
{
	padding: 4px;
} 

table.list
{
	text-align: center;
	font-family: Verdana, Geneva, Arial, Helvetica, sans-serif ;
	font-weight: normal;
	font-size: 11px;
	color: #fff;
	width: 280px;
	background-color: #666;
	border: 0px;
	border-collapse: collapse;
	border-spacing: 0px;
}

table.list td.item
{
	background-color: #CCC;
	color: #000;
	padding: 4px;
	text-align: left;
	border: 1px #fff solid;
}

table.list td.list_title,table.list td.headers
{
	background-color: #666;
	color: #fff;
	padding: 4px;
	text-align: left;
	border-bottom: 2px #fff solid;
	font-weight: bold;
} 

table.list td.list_title
{
	font-size: 16px;
} 

table.list td.headers
{
	font-size: 12px;
}
</pre>
<p>Now copy the following images to the <b>images</b> folder:<img src="http://nettuts.s3.amazonaws.com/376_kohana/add.png" border="0" />&nbsp;<img src="http://nettuts.s3.amazonaws.com/376_kohana/delete.png" border="0" />&nbsp;<img src="http://nettuts.s3.amazonaws.com/376_kohana/edit.png" border="0" /></p>
<p>That&#8217;s all. Point your browser to <b>http://localhost/kohana/index.php/album</b> and you should see something similar to this:</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/376_kohana/albums_list.jpg" border="0" /></div>
<p>If you try to create a new album or to edit an existing one you should see something similar to this:</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/376_kohana/create_album.jpg" border="0" /></div>
<h3>Step 10: Final Thoughts</h3>
<p>Of course, some improvements are required for this application but with a small amount of code, you&#8217;ve created a little web application.<br />
Now, you know how to use the MVC pattern with Kohana, and how to use database libraries and helpers. To learn more, read the official <a href="http://docs.kohanaphp.com/">documentation</a>.</p>
<p>
Thanks to Kohana,  code maintenance is an easy task, and adding new features is a cinch. I hope you enjoyed this tutorial. Stay tuned to learn more about Kohana. </p>
<ul class="webroundup">
<li>Follow us on <a href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/jXvEqRoQZmVYP9a7XfbseQUyqRI/0/da"><img src="http://feedads.g.doubleclick.net/~a/jXvEqRoQZmVYP9a7XfbseQUyqRI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/jXvEqRoQZmVYP9a7XfbseQUyqRI/1/da"><img src="http://feedads.g.doubleclick.net/~a/jXvEqRoQZmVYP9a7XfbseQUyqRI/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=xQvIVotk2rM:RiD-0buD0GU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=xQvIVotk2rM:RiD-0buD0GU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=xQvIVotk2rM:RiD-0buD0GU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=xQvIVotk2rM:RiD-0buD0GU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=xQvIVotk2rM:RiD-0buD0GU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=xQvIVotk2rM:RiD-0buD0GU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=xQvIVotk2rM:RiD-0buD0GU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=xQvIVotk2rM:RiD-0buD0GU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/xQvIVotk2rM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/tutorials/php/kohana-the-swift-php-framework/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/tutorials/php/kohana-the-swift-php-framework/</feedburner:origLink></item>
		<item>
		<title>Build a Newsletter System With PHP and MySQL: New Plus Tut</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/o7StYJ6udtw/</link>
		<comments>http://net.tutsplus.com/articles/news/build-a-newsletter-system-with-php-and-mysql-new-plus-tut/#comments</comments>
		<pubDate>Wed, 08 Jul 2009 17:07:22 +0000</pubDate>
		<dc:creator>Alex Coomans</dc:creator>
		
		<category><![CDATA[News]]></category>

		<category><![CDATA[mysql]]></category>

		<category><![CDATA[newsletter]]></category>

		<category><![CDATA[plus]]></category>

		<category><![CDATA[plus tutorial]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5742</guid>
		<description><![CDATA[<img src="http://nettutsplus.s3.amazonaws.com/20_newsletter/postimg.jpg" alt="Build a Newsletter System With PHP and MySQL: New Plus Tut" />]]></description>
			<content:encoded><![CDATA[<p>
Today, we are going to be building a newsletter system using PHP with a MySQL background. The tutorial will cover building a system that allows for multiple newsletter lists and the sending of messages to specific lists. <a href="http://net.tutsplus.com/about/join-plus/">Join today!</a>
</p>
<p><span id="more-5742"></span></p>
<div class="tutorial_image">
<img src="http://nettutsplus.s3.amazonaws.com/20_newsletter/8.png" alt="Example" style="width: 600px;" />
</div>
<div class="tutorial_image">
<img src="http://nettutsplus.s3.amazonaws.com/20_newsletter/11.png" alt="Example" style="width: 600px;" />
</div>
<h3>Join Tuts Plus</h3>
<div class="tutorial_image">
<a href="http://net.tutsplus.com/about/join-plus/"><br />
<img src="http://miscfiles.s3.amazonaws.com/banners/nettuts_468x60.jpg" border=0 alt="NETTUTS+ Screencasts and Bonus Tutorials" width=468 height=60></a></div>
<p>
For those unfamiliar, the family of TUTS sites runs a premium membership service called <a href="http://www.tutsplus.com">&#8220;TUTSPLUS&#8221;</a>. For $9 per month, you gain access to exclusive premium tutorials, screencasts, and freebies at <a href="http://net.tutsplus.com">nettuts+</a>, <a href="psd.tutsplus.com">psdtuts+</a>, and <a href="vector.tutsplus.com">vectortuts+!</a> For the price of a pizza, you&#8217;ll learn from some of the best minds in the business. <a href="http://net.tutsplus.com/about/join-plus/">Join today!</a> </p>
<ul class="webroundup">
<li>Subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/SAcAU659A0SOGcZPhdJqASp-t8k/0/da"><img src="http://feedads.g.doubleclick.net/~a/SAcAU659A0SOGcZPhdJqASp-t8k/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/SAcAU659A0SOGcZPhdJqASp-t8k/1/da"><img src="http://feedads.g.doubleclick.net/~a/SAcAU659A0SOGcZPhdJqASp-t8k/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=o7StYJ6udtw:PmEsu43JIvU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=o7StYJ6udtw:PmEsu43JIvU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=o7StYJ6udtw:PmEsu43JIvU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=o7StYJ6udtw:PmEsu43JIvU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=o7StYJ6udtw:PmEsu43JIvU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=o7StYJ6udtw:PmEsu43JIvU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=o7StYJ6udtw:PmEsu43JIvU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=o7StYJ6udtw:PmEsu43JIvU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/o7StYJ6udtw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/articles/news/build-a-newsletter-system-with-php-and-mysql-new-plus-tut/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/articles/news/build-a-newsletter-system-with-php-and-mysql-new-plus-tut/</feedburner:origLink></item>
		<item>
		<title>Authenticating Users With Facebook Connect and Google Friend Connect</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/DWYWGoJPOg8/</link>
		<comments>http://net.tutsplus.com/tutorials/other/authenticating-users-with-facebook-connect-and-google-friend-connect/#comments</comments>
		<pubDate>Wed, 08 Jul 2009 07:29:17 +0000</pubDate>
		<dc:creator>Noah Hendrix</dc:creator>
		
		<category><![CDATA[Other]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5731</guid>
		<description><![CDATA[<img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/200x200.jpg" alt="Authenticating Users With Facebook Connect and Google Friend Connect" />]]></description>
			<content:encoded><![CDATA[<p>Most social networks have API tools that allow almost any website to authenticate users through their system. In today&#8217;s tutorial, we will learn how to use these tools. Using a simple comment model, users will learn how to leave a comment within their Facebook or Google profiles. </p>
<p><span id="more-5731"></span></p>
<div class="tutorial_image">
<a href="http://nettuts.s3.amazonaws.com/375_facebookConnect/Code.zip"><img src="http://nettuts.com/wp-content/themes/nettuts/site_images/button_src_nm.jpg"></a>
</div>
<h3>The Application</h3>
<p>
  Briefly, I will go over the demo application. I have a very simple, static HTML page that shows a photo and allows the user to comment on it. In a real application you would probably save the comments to a database, but for the sake of demonstration I just save them to a text file with each line representing a new comment. This code isn&#8217;t particularly important until you get to the add comment form.
</p>
<pre name="code" class="html">
# index.php
...
&lt;div class="new-comment"&gt;
  &lt;h2 class="sub-title"&gt;Add A Comment&lt;/h2&gt;

  &lt;form action="php/savecomment.php" id="comment-form" method="post"&gt;
    &lt;div id="userbox" style="display:none;"&gt;&lt;/div&gt;

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

      Name: &lt;input id="name" name="name" type="text" /&gt;
      &lt;input id="url" name="url" type="hidden" /&gt;
      &lt;input id="image" name="image" type="hidden" /&gt;

    &lt;/div&gt;

    &lt;div class="comment"&gt;
      Comment:&lt;br /&gt;
      &lt;textarea id="comment" name="comment"&gt;&lt;/textarea&gt;
    &lt;/div&gt;
    &lt;input type="submit" value="Send Comment" /&gt;
  &lt;/form&gt;

&lt;/div&gt;
...
</pre>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/4.png" border="0" /></div>
<p>
  Here you see we have a basic form with four fields: name, url, image, and comment. I chose to hide the url and image fields because this is data we will get from Facebook and Google Friend Connect. The form is submitted to a PHP file, <strong>savecomment.php</strong>, which I won&#8217;t go over but is included in the download. In essence it takes all the post data and stores in an existing comments data file with pipe, &#8220;|&#8221;, characters separating each field. Again, not a practical technique but sufficient for our purposes. A little above the form we list out all the comments in that file by including another PHP script, <strong>readcomments.php</strong>.
</p>
<pre name="code" class="html">
# index.php
...
&lt;div class="comments"&gt;
  &lt;h2 class="sub-title"&gt;Comments&lt;/h2&gt;

  &lt;?php include("php/readcomments.php"); ?&gt;
&lt;/div&gt;
...
</pre>
<p>
  One last piece of code we need to look at is the JavaScript includes. All of our authentication is done on the client side, so I created <strong>application.js</strong> to hold the code responsible for that, and to save myself from writing too much JavaScript I included jQuery (via Google).
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/5.png" border="0" /></div>
<pre name="code" class="html">
# index.php
---
&lt;head&gt;
...
  &lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&gt;&lt;/script&gt;
  &lt;script src="./js/application.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;/head&gt;
</pre>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/6.png" border="0" /></div>
<h3>Updating The Page to Show User&#8217;s Information.</h3>
<p>
  After creating this we can move into the <strong>application.js</strong> file mentioned earlier. I decided that it would be best to create a function for each service that wrapped all the logic required in authentication. Then, after creating these for both services I extracted out common code to keep the code concise. After creating the file declare a function called <strong>update_userbox()</strong>
</p>
<pre name="code" class="js">
# application.js
---
//Generic updates #userbox with info retrieved
//from services
function update_userbox(name, image, url, logout) {

  //populate the data in #userbox and show it
  $('#userbox').html( "&lt;a href='"+url+"'&gt;"
                    + "&lt;img alt='"+name+"' src='"+image+"' /&gt;"
                    + "Logged in as " + name + "&lt;/a&gt; "
                    + "(&lt;a href='./index.php' onclick='" + logout + "'&gt;logout&lt;/a&gt;)" ).show();

  //hide name input and service
  //login buttons
  $('#userinfo').hide();

  //populate the values of the inputs
  //using data from service
  $('#name').val(name);
  $('#url').val(url);
  $('#image').val(image);

}
</pre>
<p>
  This function is generic and can be used with either service, and as more spring up could probably be used in others as well. The purpose of this is to insert HTML into an empty div called <strong>#userbox</strong> so the user has a visual understanding that they logged into a service. This is done by hiding the name box, and showing a profile image from the remote service along with their name and a logout link to disconnect from the service. Also behind the scenes we fill in the name, url, and image inputs so they are submitted to the server along with the comment for saving to our database file. You can see this is done by passing in four variables:
</p>
<ul>
<li>name: the user&#8217;s name they provided to the service</li>
<li>image: a url to the user&#8217;s profile image</li>
<li>url: a url to the user&#8217;s profile on the service</li>
<li>logout: a string of JS code to execute when logout is pressed</li>
</ul>
<p>
  These are all pretty straightforward, except the logout variable. This can be explained when you look at the APIs that FB and GFC offer. Each has function that will notify the service that the user wishes to be logged out, this is how I chose to pass that function call into the logout link.
</p>
<h3>Facebook Connect - Getting Your API Key</h3>
<p>
  We will start with <a href="http://developers.facebook.com/connect.php">Facebook Connect</a>. The first thing we will need to do is <a href="http://www.facebook.com/developers/createapp.php">create an application</a> on Facebook&#8217;s Developers site. It seems a bit odd at first that we have to create a Facebook application for this, but as far as I can tell it is only to receive the API key and to register your URLs with their developer program.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/2.png" border="0" /></div>
<p>
  After you have created the application we need to edit some settings, on the left side of the screen you will see tabs, click on <a href="http://www.facebook.com/developers/editapp.php?app_id=100603521509&#038;view=connect">Connect</a>. Here you need to enter the <strong>Connect URL</strong> which is the URL where the root of your site exists. I also chose to upload a picture, and I recommend all websites do this as it gives you some visual branding.
</p>
<p>
  Alright now you can save these changes and it will take you to the application summary page. Here is where we can find the application API key, so go ahead and copy that on to your clipboard.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/3.png" border="0" /></div>
<h3>Adding A Cross-Domain Receiver</h3>
<p>
  Facebook architected their connect API to work entirely on the client side. This tutorial will require no server side code to authenticate users. This is done through some intricate AJAX techniques where Facebook passes data back and forth via iframes to circumvent the same-origin policy implemented by most browsers. Part of this process requires that we <a href="http://wiki.developers.facebook.com/index.php/Cross-domain_communication_channel">place a file</a> on our server that Facebook can interact with to verify our identity. So at the top-level of your domain create a file called <strong>xd_receiver.html</strong> and insert this code.
</p>
<pre name="code" class="html">
# xd_receiver.html
---
&lt;pre name="code" class="html"&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;body&gt;
    &lt;script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
&lt;/pre&gt;
</pre>
<h3>The Facebook Connect Button</h3>
<p>
  Facebook requires us to jump through a few hoops to get everything working, first of which is we need to include a JS file from the Facebook website and run the <a href="http://wiki.developers.facebook.com/index.php/JS_API_M_FB.Facebook.Init">init()</a> function in our <strong>index.php</strong> file at very bottom just above the closing &lt;/body&gt; tag.
</p>
<pre name="code" class="html">
# index.php
---
&lt;!-- Facebook API Includes --&gt;
&lt;script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
  FB.init("FB_API_KEY", "xd_receiver.htm", {"ifUserConnected" : auth_using_fb});
&lt;/script&gt;
</pre>
<p>
  There are a few things we need to look at in this function. First, be sure to replace <strong>FB_API_KEY</strong> with your API key. Next we have a string representing the path to our cross-domain receiver file which should be at the root of your application directory. Finally, we can pass in a hash of options. We want to maintain users&#8217; login state so we tell Facebook to run a function <strong>auth_using_fb</strong> (we will create this in a few moments) if the user is already connected to our site. This means that if the user reloads the page it will still show them as logged in so they don&#8217;t have to re-login on every page.
</p>
<p>
  Next we have to create the actual login button, this requires using <a href="http://wiki.developers.facebook.com/index.php/XFBML">XFBML</a>, Facebook Markup Language which is an extension to HTML. The X denotes code that is inserted on 3rd party websites and not on Facebook&#8217;s website. Somewhere on the page we have to insert the tag <a href="http://wiki.developers.facebook.com/index.php/Fb:login-button">Fb:login-button</a> and a few options.
</p>
<pre name="code" class="html">
  &lt;fb:login-button length="long" onlogin="auth_using_fb();"&gt;&lt;/fb:login-button&gt;
</pre>
<p>
  I chose to put this next to my name textbox so the user could easily see it when they go to add a comment. Notice we have two attributes <strong>length</strong> and <strong>onlogin</strong>. <strong>Length</strong> allows us to specify the text on the button and has two options: short (the default) and long. Short says <strong>Connect</strong> and long says <strong>Connect with Facebook</strong>. <strong>Onlogin</strong> works a lot like <strong>onclick</strong> or <strong>onmouseover</strong> and allows us to execute JS when the user successfully authenticates with our site through Facebook. We call the same function we mentioned earlier, <strong>auth_using_fb()</strong>, but before we can create that we need to make one more change. At the top of the page in the HTML tag we need to tell the browser we are using more than one markup language.
</p>
<pre name="code" class="html">
# index.php
---
&lt;html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml"&gt;
</pre>
<p>
  The <a href="http://www.w3schools.com/tags/att_html_xmlns.asp">xmlns</a> attribute specifies the xml namespace for the document. The first is the standard <strong>xhtml</strong>, and the second is the new facebook markup language, this helps make our document W3C compliant.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/7.png" border="0" /></div>
<h3>Writing the Javascript</h3>
<p>
  Now we are going to go back to <strong>application.js</strong> and write the <strong>auth_using_fb()</strong> function.
</p>
<pre name="code" class="js">
# application.js
---
//Facebook Connect
function auth_using_fb() {
  //get the users data from FB
  var viewer  = FB.Facebook.apiClient.fql_query(

      'SELECT name, pic_square_with_logo,profile_url FROM user WHERE uid='+FB.Facebook.apiClient.get_session().uid,

      function(results) {
        update_userbox( results[0].name,
                        results[0].pic_square_with_logo,
                        results[0].profile_url,
                        'FB.Connect.logoutAndRedirect("./index.php");return false;')
      }
  );
}
</pre>
<p>
  This is the function we use to interface with Facebook&#8217;s data, and retrieve users&#8217; data. The login button we created earlier actually has the functionality for signing the user into Facebook built-in, but if want to grab the information about the user we must request it separately. The first line of code in the function is a call to the Facebook API method, <a href="http://wiki.developers.facebook.com/index.php/JS_API_M_FB.ApiClient.Fql_query">fql_query()</a>. This function allows us to use Facebook&#8217;s SQL like query language to fetch the user&#8217;s data. We only need the three columns we discussed earlier: name, picture, and url. The Facebook Developer wiki has <a href="http://wiki.developers.facebook.com/index.php/FQL_Tables">a page</a> containing all the various tables that you can query for information. It is important to add the <strong>WHERE</strong> clause that limits to the currently logged in user. The second parameter of <strong>fql_query</strong> is a callback function that is passed an array of the results. We just need to take the first result in the array and send each property to our <strong>update_userbox()</strong> function along with the logout JS call. It is important to include <strong>&#8220;return false;&#8221;</strong> after the <a href="http://wiki.developers.facebook.com/index.php/JS_API_M_FB.Connect.LogoutAndRedirect">logoutAndRedirect()</a> call because otherwise it causes the page to reload before the API can log out the user.
</p>
<p>
  And amazingly that is all we need to do for Facebook Connect to work, go ahead and try it out!
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/8.png" border="0" /></div>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/9.png" border="0" /></div>
<h3>Google Friend Connect - API Key</h3>
<p>
  Much like Facebook Connect, Google Friend Connect requires us to <a href="http://www.google.com/friendconnect/admin/site/setup?hl=en_US">sign up</a> for an API Key. This is far quicker than Facebook Connect as they have an easy-to-use wizard that walks you through it all. First you need to provide the application name and URL just like in Facebook Connect.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/10.png" border="0" /></div>
<p>
  Next it instructs you to upload a few files to your server for cross-domain AJAX support, again just like Facebook Connect. Seeing a trend here?
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/11.png" border="0" /></div>
<p>
  The final step will verify that everything is setup properly. Google calls the API Key the Site ID, but it acts the exact same Facebook&#8217;s API key.
</p>
<h3>Including the Necessary Files</h3>
<p>
  Next we need to include the proper JS files at the bottom of our page after the Facebook files. We also need to implement the <a href="http://code.google.com/apis/friendconnect/js_api.html">initOpenSocialApi()</a> method of the Google Friend Connect API. This takes one parameter in the form of a hash of options. The only required option is <strong>site</strong> which is our Site ID we collected earlier.
</p>
<pre name="code" class="js">
# index.php
---
&lt;!-- Google API Includes --&gt;
&lt;script src="http://www.google.com/friendconnect/script/friendconnect.js?v=0.8" type="text/javascript"&gt;&lt;/script&gt;

&lt;!-- Initialize the Google Friend Connect OpenSocial API. --&gt;
&lt;script type="text/javascript"&gt;
  google.friendconnect.container.setParentUrl('/envato/nologin/' /* location of rpc_relay.html and canvas.html */);
  google.friendconnect.container.initOpenSocialApi({
    site: 'GFC_API_KEY',
    onload: function(securityToken) { auth_using_gfc(); }
  });
  google.friendconnect.renderSignInButton({id:"google-login",style:'long'})
&lt;/script&gt;
</pre>
<p>
  We also need to page in a callback function to execute when the user is authenticated with Google Friend Connect. Additionally we have to call a function that renders the sign in button, this is very similar to the XFBML markup we used earlier except Google decided to stick with plain HTML. This function requires we pass it a DOM id of the element we want the signin button to be created in, I made a div just below the FB login button with an id of <strong>google-login</strong>. We also pass in the <strong>style:&#8217;long&#8217;</strong> option so that it is similar to our Facebook button.
</p>
<pre name="code" class="html">
&lt;div class="services"&gt;
  &lt;fb:login-button length="long" onlogin="auth_using_fb();"&gt;&lt;/fb:login-button&gt;
  &lt;div id="google-login"&gt;&lt;/div&gt;
&lt;/div&gt;
</pre>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/12.png" border="0" /></div>
<h3>Writing the JavaScript</h3>
<p>
    Google Friend Connect is similar in many ways to Facebook Connect, which of course makes our job all the easier. One language difference I found is that Google&#8217;s API tends to be a bit more verbose in nature so we will split our explanation of <strong>auth_using_gfc()</strong> into two parts.
</p>
<pre name="code" class="js">
//Google Friend Connect
function auth_using_gfc() {
  //Request GFC to send extra profile data
  var params = {};
      params[opensocial.DataRequest.PeopleRequestFields.PROFILE_DETAILS] =
      [opensocial.Person.Field.URLS];

  // Create a request to grab the current viewer.
  var req = opensocial.newDataRequest();
  req.add(req.newFetchPersonRequest('VIEWER', params), 'viewer_data');
...
</pre>
<p>
  The first thing we do is declare the <strong>params</strong> variable as an empty hash. This will contain the options we need to send with our request to Google, because by default we do not receive the user&#8217;s profile URL. Next we create a request object that will actually make the request to Google for the user&#8217;s profile data. The <strong>add()</strong> method takes two arguments a <strong>newFetchPersonRequest()</strong> object and then a unique string to identify the data. <strong>VIEWER</strong> is a constant representing the currently logged in user.
</p>
<pre name="code" class="js">
// Sent the request
req.send(function(data) {

  // If the view_data had an error, then user is not signed in
  if (!data.get('viewer_data').hadError()) {
    //get the users data from GFC
    var viewer = data.get('viewer_data').getData();

    update_userbox( viewer.getDisplayName(),
                    viewer.getField(opensocial.Person.Field.THUMBNAIL_URL),
                    viewer.getField(opensocial.Person.Field.URLS)[0].getField('address'),
                    'google.friendconnect.requestSignOut()' );
  }

});
</pre>
<p>
  The last part of the function is the actual request for data, using the <strong>send()</strong> method which takes one argument of a callback function. We declare the function inline and we have an if statement that checks weather the request received an error. If it doesn&#8217;t we assume everything went alright and we declare a variable called view that holds the data received from the request. This data is then passed into our <strong>update_userbox()</strong> function. The only thing to note here is the the third argument that passes in the user&#8217;s URL. Google allows users to enter multiple profile URLs (such as Facebook, Twitter, etc.) and we only need the first one which is the Google profile URL. The final argument is our string of JS to execute that signs the user out which also reloads the page.
</p>
<p>
  This is all we need to do, so go ahead and try it out! One really nice thing you&#8217;ll notice is that user&#8217;s don&#8217;t have to have a Google account to login they can also use their AOL/AIM, Yahoo!, Netlog, or Open ID accounts.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/13.png" border="0" /></div>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/375_facebookConnect/./images/14.png" border="0" /></div>
<h3>Conclusion</h3>
<p>
  While this specific example is not production ready, hopefully you can see how easy it would be for us to implement this into our existing applications. I encourage everyone to take a good look over the documentation Facebook and Google offer.
</p>
<ul>
<li><a href="http://wiki.developers.facebook.com/index.php/Facebook_Connect">Facebook Connect Documentation</a></li>
<li><a href="http://wiki.developers.facebook.com/index.php/Facebook_Connect_Tutorial1">FBC Tutorial</a></li>
<li><a href="http://developers.facebook.com/tools.php?api">FQL Simulator</a></li>
<li><a href="http://code.google.com/apis/friendconnect/js_api.html">Google Friend Connect Documentation</a></li>
<li><a href="http://code.google.com/apis/friendconnect/code.html">GFC Example Code</a></li>
<li><a href="http://code.google.com/apis/ajax/playground/?exp=friendconnect">GFC Simulator</a></li>
</ul>
<p>
  I hope you enjoyed this tutorial, and if there is enough interest, I will write a follow-up tutorial on how this can be further integrated using PHP on the server-side. As always, if anyone needs help or you can find me on <a href="http://twitter.com">Twitter</a>, <a href="http://twitter.com/noahhendrix">@noahhendrix</a>.
</p>
<ul class="webroundup">
<li>Follow us on <a href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/t6Lo1VJ5Yy3hMI7AGCZRC66bFuI/0/da"><img src="http://feedads.g.doubleclick.net/~a/t6Lo1VJ5Yy3hMI7AGCZRC66bFuI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/t6Lo1VJ5Yy3hMI7AGCZRC66bFuI/1/da"><img src="http://feedads.g.doubleclick.net/~a/t6Lo1VJ5Yy3hMI7AGCZRC66bFuI/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=DWYWGoJPOg8:97OlpoLJD7U:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=DWYWGoJPOg8:97OlpoLJD7U:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=DWYWGoJPOg8:97OlpoLJD7U:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=DWYWGoJPOg8:97OlpoLJD7U:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=DWYWGoJPOg8:97OlpoLJD7U:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=DWYWGoJPOg8:97OlpoLJD7U:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=DWYWGoJPOg8:97OlpoLJD7U:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=DWYWGoJPOg8:97OlpoLJD7U:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/DWYWGoJPOg8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/tutorials/other/authenticating-users-with-facebook-connect-and-google-friend-connect/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/tutorials/other/authenticating-users-with-facebook-connect-and-google-friend-connect/</feedburner:origLink></item>
		<item>
		<title>HTML 5 and CSS 3: The Techniques You’ll Soon Be Using</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/6Ct44CRbhpk/</link>
		<comments>http://net.tutsplus.com/tutorials/html-css-techniques/html-5-and-css-3-the-techniques-youll-soon-be-using/#comments</comments>
		<pubDate>Tue, 07 Jul 2009 05:15:26 +0000</pubDate>
		<dc:creator>Mads Kjaer</dc:creator>
		
		<category><![CDATA[HTML & CSS]]></category>

		<category><![CDATA[CSS]]></category>

		<category><![CDATA[css3]]></category>

		<category><![CDATA[css3 html]]></category>

		<category><![CDATA[html 5]]></category>

		<category><![CDATA[html5]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5708</guid>
		<description><![CDATA[<img src="http://nettuts.s3.amazonaws.com/373_html5/200x200.png" alt="HTML 5 and CSS 3: The Techniques You'll Soon be Using" />]]></description>
			<content:encoded><![CDATA[<p>In this tutorial, we are going to build a blog page using next-generation techniques from HTML 5 and CSS 3. The tutorial aims to demonstrate how we will be building websites when the specifications are finalized and the browser vendors have implemented them. If you already know HTML and CSS, it should be easy to follow along.
</p>
<p><span id="more-5708"></span></p>
<div class="tutorial_image">
<a href="http://nettuts.s3.amazonaws.com/373_html5/final.zip"><img src="http://nettuts.com/wp-content/themes/nettuts/site_images/button_src_nm.jpg"></a><br />
<a href="http://nettuts.s3.amazonaws.com/373_html5/final/index.html"><img src="http://nettuts.com/wp-content/themes/nettuts/site_images/button_demo_nm.jpg"></a>
</div>
<h3>What We Are Going to Build</h3>
<p>This is what our page is going to look like when finished:</p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/373_html5/final.jpg" alt="Diagram of basic structure" />
</div>
<p>Pretty much your every day blog design. Header with title, horizontal navigation, content area with comments and form, sidebar and a footer. Nothing too special. Let&#8217;s get building.</p>
<h3>HTML 5</h3>
<p>HTML 5 is the next major version of HTML. It introduces a bunch of new elements that will make our pages more semantic. This will make it a lot easier for search engines and screenreaders to navigate our pages, and improve the web experience for everyone. In addition, HTML 5 will also include fancy APIs for drawing graphics on screen, storing data offline, dragging and dropping, and a lot more. Let&#8217;s get started marking up the blog page.</p>
<h3>Basic Structure</h3>
<p>Before we begin marking up the page we should get the overall structure straight:</p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/373_html5/structure.png" alt="Diagram of basic structure" />
</div>
<p>In HTML 5 there are specific tags meant for marking up the header, navigation, sidebar and footer. First, take a look at the markup and I&#8217;ll explain afterwards:</p>
<pre name="code" class="html">
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
	&lt;title&gt;Page title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
	&lt;header&gt;
		&lt;h1&gt;Page title&lt;/h1&gt;
	&lt;/header&gt;
	&lt;nav&gt;
		&lt;!-- Navigation --&gt;
	&lt;/nav&gt;
	&lt;section id="intro"&gt;
		&lt;!-- Introduction --&gt;
	&lt;/section&gt;
	&lt;section&gt;
		&lt;!-- Main content area --&gt;
	&lt;/section&gt;
	&lt;aside&gt;
		&lt;!-- Sidebar --&gt;
	&lt;/aside&gt;
	&lt;footer&gt;
		&lt;!-- Footer --&gt;
	&lt;/footer&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>It still looks like HTML markup, but there are a few things to note:</p>
<ul>
<li>
		In HTML 5, there is only one doctype. It is declared in the beginning of the page by &lt;!doctype html&gt;. It simply tells the browser that it&#8217;s dealing with an HTML-document.
	</li>
<li>
		The new tag header is wrapped around introductory elements, such as the page title or a logo. It could also contain a table of contents or a search form. Every header typically contains a heading tag from &lt;h1&gt; to &lt;h6&gt;. In this case the header is used to introduce the whole page, but we&#8217;ll use it to introduce a section of the page a little later.
	</li>
<li>
		The nav-tag is used to contain navigational elements, such as the main navigation on a site or more specialized navigation like next/previous-links.
	</li>
<li>
		The section-tag is used to denote a section in the document. It can contain all kinds of markup and multiple sections can be nested inside each other.
	</li>
<li>
		aside is used to wrap around content related to the main content of the page that could still stand on it&#8217;s own and make sense. In this case we&#8217;re using it for the sidebar.
	</li>
<li>The footer-tag should contain additional information about the main content, such as info about who wrote it, copyright information, links to related documents and so on.</li>
</ul>
<p>Instead of using divs to contain different sections of the page we are now using appropriate, semantic tags. They will make it a lot easier for search engines and screen readers to figure out what&#8217;s what in a page.</p>
<h3>Marking Up the Navigation</h3>
<p>The navigation is marked up exactly like we would do it in HTML 4 or XHTML, using an unordered list. The key is that this list is placed inside the nav-tags.</p>
<pre name="code" class="html">
&lt;nav&gt;
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="#"&gt;Blog&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;About&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;Archives&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#"&gt;Contact&lt;/a&gt;&lt;/li&gt;
		&lt;li class="subscribe"&gt;&lt;a href="#"&gt;Subscribe via. RSS&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
&lt;/nav&gt;
</pre>
<h3>Marking Up the Introduction</h3>
<p>We have already defined a new section in the document using the section tag. Now we just need some content.</p>
<pre name="code" class="html">
&lt;section id="intro"&gt;
	&lt;header&gt;
		&lt;h2&gt;Do you love flowers as much as we do?&lt;/h2&gt;
	&lt;/header&gt;
	&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.&lt;/p&gt;
&lt;/section&gt;
</pre>
<p>We add an id to the section tag so we can identify it later when styling. We use the header tag to wrap around the introductory h2 element. In addition to describing a whole document, the header-tag should also be used to describe individual sections.</p>
<h3>Marking Up the Main Content Area</h3>
<p>Our main content area consists of three sections: the blog post, the comments and the comment form. Using our knowledge about the new structural tags in HTML 5, it should be easy to mark it up.</p>
<h4>Marking up the Blog Post</h4>
<p>Go through the markup and I&#8217;ll explain the new elements afterwards.</p>
<pre name="code" class="html">
&lt;section&gt;
	&lt;article class="blogPost"&gt;
		&lt;header&gt;
			&lt;h2&gt;This is the title of a blog post&lt;/h2&gt;
			&lt;p&gt;Posted on &lt;time datetime="2009-06-29T23:31:45+01:00"&gt;June 29th 2009&lt;/time&gt; by &lt;a href="#"&gt;Mads Kjaer&lt;/a&gt; - &lt;a href="#comments"&gt;3 comments&lt;/a&gt;&lt;/p&gt;
		&lt;/header&gt;
		&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod tellus eu orci imperdiet nec rutrum lacus blandit. Cras enim nibh, sodales ultricies elementum vel, fermentum id tellus. Proin metus odio, ultricies eu pharetra dictum, laoreet id odio...&lt;/p&gt;
	&lt;/article&gt;
&lt;/section&gt;
</pre>
<p>We start a new section and wrap the whole blog post in an article-tag. The article tag is used to denote an independent entry in a blog, discussion, encyclopedia, etc. and is ideal to use here. Since we are viewing the details of a single post we only have one article, but on the front page of the blog we would wrap each post in an article-tag.</p>
<p>The header element is used to present the header and metadata about the blog post. We tell the user when the post was written, who wrote it and how many comments it has. Note that the timestamp is wrapped in a <time>-tag. This tag is also new to HTML 5 and is used to mark up a specific place in time. The contents of the datetime attribute should be:</p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/373_html5/time.png" alt="Diagram describing use of the datetime HTML attribute" />
</div>
<ol>
<li>The year followed by a figure dash (a minus sign to you non-typography nerds)</li>
<li>The month followed by a figure dash</li>
<li>The date</li>
<li>A capital T to denote that we are going to specify the local time</li>
<li>The local time in the format hh:mm:ss</li>
<li>The time zone relative to GMT. I&#8217;m in Denmark which is 1 hour after GMT, so I write +01. If you were in Colorado you would be 7 hours behind GMT, and you would write -07.</li>
</ol>
<h4>Marking up the Comments</h4>
<p>Marking up the comments is pretty straight-forward. No new tags or attributes are used.</p>
<pre name="code" class="html">
&lt;section id="comments"&gt;
	&lt;header&gt;
		&lt;h3&gt;Comments&lt;/h3&gt;
	&lt;/header&gt;
	&lt;article&gt;
		&lt;header&gt;
			&lt;a href="#"&gt;George Washington&lt;/a&gt; on &lt;time datetime="2009-06-29T23:35:20+01:00"&gt;June 29th 2009 at 23:35&lt;/time&gt;
		&lt;/header&gt;
		&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.&lt;/p&gt;
	&lt;/article&gt;
	&lt;article&gt;
		&lt;header&gt;
			&lt;a href="#"&gt;Benjamin Franklin&lt;/a&gt; on &lt;time datetime="2009-06-29T23:40:09+01:00"&gt;June 29th 2009 at 23:40&lt;/time&gt;
		&lt;/header&gt;
		&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.&lt;/p&gt;
	&lt;/article&gt;
&lt;/section&gt;
</pre>
<h4>Marking up the Comment Form</h4>
<p>Several enhancements to forms have been introduced in HTML 5. You longer have to do client-side validation of required fields, emails, etc. The browser takes care of this for you.</p>
<pre name="code" class="html">
&lt;form action="#" method="post"&gt;
	&lt;h3&gt;Post a comment&lt;/h3&gt;
	&lt;p&gt;
		&lt;label for="name"&gt;Name&lt;/label&gt;
		&lt;input name="name" id="name" type="text" required /&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;label for="email"&gt;E-mail&lt;/label&gt;
		&lt;input name="email" id="email" type="email" required /&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;label for="website"&gt;Website&lt;/label&gt;
		&lt;input name="website" id="website" type="url" /&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;label for="comment"&gt;Comment&lt;/label&gt;
		&lt;textarea name="comment" id="comment" required&gt;&lt;/textarea&gt;
	&lt;/p&gt;
	&lt;p&gt;&lt;input type="submit" value="Post comment" /&gt;&lt;/p&gt;
&lt;/form&gt;
</pre>
<p>There are new two new types of inputs, email and url. Email specifies that the user should enter a valid E-mail, and url that the user should enter a valid website address. If you write required as an attribute, the user cannot submit an empty field. &#8220;Required&#8221; is a boolean attribute, new to HTML 5. It just means that the attribute is to be declared without a value.</p>
<h3>Marking up the Sidebar and Footer</h3>
<p>The markup of the sidebar and footer is extremely simple. A few sections with some content inside the appropriate aside- and footer-tags.</p>
<p>You can view the final, unstyled markup <a href="http://nettuts.s3.amazonaws.com/373_html5/markup/index.html">here</a>. Now for the styling.</p>
<h3>Styling with CSS 3</h3>
<p>CSS 3 builds upon the principles about styles, selectors and the cascade that we know so well from earlier versions of CSS. It adds loads of new features, including new selectors, pseudo-classes and properties. Using these new features it becomes a lot easier to set up your layout. Let&#8217;s dive in.</p>
<h3>Basic Setup</h3>
<p>To start off with we are going to define some basic rules concerning typography, background color of the page, etc. You&#8217;ll recognize all of this from CSS 2.1</p>
<pre name="code" class="css">
/* Makeshift CSS Reset */
{
	margin: 0;
	padding: 0;
}

/* Tell the browser to render HTML 5 elements as block */
header, footer, aside, nav, article {
	display: block;
}

body {
	margin: 0 auto;
	width: 940px;
	font: 13px/22px Helvetica, Arial, sans-serif;
	background: #f0f0f0;
}

h2 {
	font-size: 28px;
	line-height: 44px;
	padding: 22px 0;
}

h3 {
	font-size: 18px;
	line-height: 22px;
	padding: 11px 0;
}

p {
	padding-bottom: 22px;
}
</pre>
<p>First we reset margin- and padding-styles with a simple rule. In a production environment I would use a more complete CSS Reset such as Eric Meyer&#8217;s (for CSS 2.1) but for the scope of the tutorial this will do.</p>
<p>We then tell the browser to render all the new HTML 5 elements as block. The browsers are fine with elements they don&#8217;t recognize (this is why HTML 5 is somewhat backwards compatible), but they don&#8217;t know how those elements should be rendered by default. We have to tell them this until the standard is implemented across the board.</p>
<p>Also note how I&#8217;ve chosen to size the fonts in pixels instead of ems or %. This is to maintain the progressive nature of the tutorial. When the major browsers one day are completely finished implementing HTML 5 and CSS 3 we will all have access to page zooming instead of just text resizing. This eliminates the need to define sizes in relative units, as the browser will scale the page anyway.</p>
<p><a href="http://nettuts.s3.amazonaws.com/373_html5/basic_styling/index.html">See what the page looks like</a> with the basic styling applied. Now we can move on to styling the rest of the page. No additional styles are required for the header, so we&#8217;ll go straight to the navigation.</p>
<h3>Styling the Navigation</h3>
<p>It is important to note that the width of the body has been defined as 940px and that it has been centered. Our navigation bar needs to span the whole width of the window, so we&#8217;ll have to apply some additional styles:</p>
<pre name="code" class="css">
nav {
	position: absolute;
	left: 0;
	width: 100%;
	background: url("nav_background");
}
</pre>
<p>We position the nav-element absolutely, align it to the left of the window and make it span the whole width. We&#8217;ll center the nested list to display it within the boundaries of the layout:</p>
<pre name="code" class="css">
nav ul {
	margin: 0 auto;
	width: 940px;
	list-style: none;
}
</pre>
<p>Now we&#8217;ll define some additional styles to make the navigation items look prettier and align them to the grid the layout is based on. I&#8217;ve also included a style for highlighting the page the user is on, and some custom styling for the subscription-link.</p>
<pre name="code" class="css">
nav ul li {
	float: left;
}

	nav ul li a {
		display: block;
		margin-right: 20px;
		width: 140px;
		font-size: 14px;
		line-height: 44px;
		text-align: center;
		text-decoration: none;
		color: #777;
	}

		nav ul li a:hover {
			color: #fff;
		}

		nav ul li.selected a {
			color: #fff;
		}

		nav ul li.subscribe a {
			margin-left: 22px;
			padding-left: 33px;
			text-align: left;
			background: url("rss.png") left center no-repeat;
		}
</pre>
<h3>Styling the Introduction</h3>
<p>The markup for the introduction is pretty simple: A section with a heading and a paragraph of text. However, we&#8217;ll use some new CSS 3 tricks to make it look more appealing.</p>
<pre name="code" class="css">
#intro {
	margin-top: 66px;
	padding: 44px;
	background: #467612 url("intro_background.png") repeat-x;
	background-size: 100%;
	border-radius: 22px;
}
</pre>
<p>We are using two new properties. The first one is background-size, which allows you to scale the background-image. In our case, we scale it to 100% on both axes. If the box expands as we add more content to it, the gradient background will scale as well. This is something that was not possible in CSS 2.1 without non-semantic markup and miscellaneous browser issues.</p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/373_html5/background-size.png" src="Illustration of how the CSS property background-size works" />
</div>
<p>The second new property is border-radius, which applies rounded corners to the element. The radius of our rounded corners are 22px in every corner. You could specify different values for each corner or choose to only round individual corners.</p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/373_html5/border-radius.png" src="Illustration of how the CSS property border-radius works" /></div>
<p>Unfortunately, neither of the properties are fully implemented into the major browsers. However, we can get some support by using vendor-specific attributes. Background-size is supported by newer versions of Safari, Opera and Konqueror. Border-radius is supported by newer versions of Safari and Firefox.</p>
<pre name="code" class="css">
#intro {
	...
	/* Background-size not implemented yet */
	-webkit-background-size: 100%;
	-o-background-size: 100%;
	-khtml-background-size: 100%;

	/* Border-radius not implemented yet */
 	-moz-border-radius: 22px;
	-webkit-border-radius: 22px;
}
</pre>
<p>Since we have a background-color defined, there will be no major problems in browsers that don&#8217;t support background-size, such as Firefox. Now we just need to style the heading and the text.</p>
<pre name="code" class="css">
#intro h2, #intro p¬†{
	width: 336px;
}

#intro h2 {
	padding: 0 0 22px 0;
	font-weight: normal
	color: #fff;
}

#intro p {
	padding: 0;
	color: #d9f499;
}
</pre>
<p>The flower image can be added easily by giving #intro a second background image, something that CSS 3 supports.</p>
<pre name="code" class="css">
#intro {
	...
	background: #467612 url("intro_background.png") top left (287px 100%) repeat-x,
			url("intro_flower.png") top right (653px 100%) no-repeat;
	...
}
</pre>
<p>We give the two background images explicit dimensions to ensure that they don&#8217;t overlap, and we&#8217;re set. Note the shorthand notation of background-size.</p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/373_html5/multiple_bgs.png" src="Illustration demonstrating how we could set up two background images using CSS 3" /></div>
<p>Unfortunately, no browser reliably supports this yet, so we&#8217;ll have to do it the old-fashioned way: by including an inline image and positioning it using CSS. See the final example to see how it was done.</p>
<h3>Styling the Content Area and Sidebar</h3>
<p>The content area and sidebar are going to be aligned beside each other. Traditionally you would do this by using floats, but in CSS 3 we are going to use tables!</p>
<p>&#8220;What?! Tables?&#8221; you might ask and look confused. You probably learned years ago that using tables for web layout is a big no-no, and it still is. You should never use the table-element to mark up a layout. However, in CSS 3 we can make elements behave like tables without it ever showing in the markup! To start off with, we&#8217;re going to need some divs to group the sections in a little more logical manner.</p>
<pre name="code" class="html">
&lt;div id="content"&gt;
	&lt;div id="mainContent"&gt;
		&lt;section&gt;
			&lt;!-- Blog post --&gt;
		&lt;/section&gt;
		&lt;section id="comments"&gt;
			&lt;!-- Comments --&gt;
		&lt;/section&gt;
		&lt;form&gt;
			&lt;!-- Comment form --&gt;
		&lt;/form&gt;
	&lt;/div&gt;
	&lt;aside&gt;
		&lt;!-- Sidebar --&gt;
	&lt;/aside&gt;
&lt;/div&gt;
</pre>
<p>Everything still makes sense semantically, but now we can style it. We want the #content div to behave like a table, with #mainContent and aside as table-cells. With CSS 3, this is very easy:</p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/373_html5/table_cells.png" src="Diagram illustrating the added structure and the CSS-properties applied" /></div>
<pre name="code" class="css">
#content {
	display: table;
}

	#mainContent {
		display: table-cell;
		width: 620px;
		padding-right: 22px;
	}

	aside {
		display: table-cell;
		width: 300px;
	}
</pre>
<p>That&#8217;s all! No more floating, faux column background images, clearing or collapsing margins. We&#8217;ve made the elements behave like a table, and this makes it much easier for us to do layout.</p>
<h3>Styling the Blog Post</h3>
<p>The styling of the post header is rather trivial so I&#8217;ll skip to the fun part: the multi-column layout.</p>
<h4>Multiple columns</h4>
<p>Multiple columns of text was previously impossible without manually splitting the text, but with CSS 3 it&#8217;s a piece of cake, although we have to add a div around the multiple paragraphs for this to work with current browsers.</p>
<pre name="code" class="html">
&lt;div&gt;
	&lt;p&gt;Lorem ipsum dolor sit amet...&lt;/p&gt;
	&lt;p&gt;Pellentesque ut sapien arcu...&lt;/p&gt;
	&lt;p&gt;Vivamus vitae nulla dolor...&lt;/p&gt;
	...
&lt;/div&gt;
</pre>
<p>Now we can add two simple properties and call it a day.</p>
<pre name="code" class="css">
.blogPost div {
	column-count: 2;
	column-gap: 22px;
}
</pre>
<p>We want 2 columns and a gap of 22px between the columns. The additional div is needed because there is currently no supported way of making an element span more than one column. In the future, however, you&#8217;ll be able to specify the column-span property, and we could just write:</p>
<pre name="code" class="css">
.blogPost {
	column-count: 2;
	column-gap: 22px;
}

	.blogPost header {
		column-span: all;
	}
</pre>
<p>Of course the column-count and column-gap properties are only supported by some browsers, Safari and Firefox. We have to use the vendor-specific properties for now.</p>
<pre name="code" class="css">
.blogPost div {
	/* Column-count not implemented yet */
	-moz-column-count: 2;
	-webkit-column-count: 2;

	/* Column-gap not implemented yet */
	-moz-column-gap: 22px;
	-webkit-column-gap: 22px;
}
</pre>
<h4>Box shadow</h4>
<p>If you look closely at the image in the blog post you&#8217;ll see a drop-shadow. We are able to generate this using CSS 3 and the box-shadow property.</p>
<pre name="code" class="css">
.blogPost img {
	margin: 22px 0;
	box-shadow: 3px 3px 7px #777;
}
</pre>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/373_html5/shadow_rendering.png" alt="Illustration describing how the browsers render the box-shadow CSS property" /></div>
<p>The first &#8220;3px&#8221; tells the browser where we want the shadow to stop horizontally. The second &#8220;3px&#8221; tells it where we want the shadow to stop vertically. The last &#8220;7px&#8221; is how blurred the border should be. If you set it to 0 it will be completely solid. Last but not least we define the base color of the shadow. This color is of course faded, depending on how much you blur the shadow.</p>
<p>It probably comes as no surprise that this property is not implemented in all browsers yet. In fact, it only works in Safari, and you have to use the vendor-specific property.</p>
<pre name="code" class="css">
.blogPost img {
	margin: 22px 0;
	-webkit-box-shadow: 3px 3px 7px #777;
}
</pre>
<h3>Zebra-striping the Comments</h3>
<p>Zebra-striping, or highlighting every second element in a series, has traditionally involved selecting all the elements via javascript, then looping through them and highlighting all the odd elements. CSS 3 introduces the pseudo-class &#8220;nth-child&#8221;, which makes it ridiculously simple to do this without javascript. We&#8217;ll use it to zebra-stripe the comments.</p>
<pre name="code" class="css">
section#comments article:nth-child(2n+1) {
	padding: 21px;
	background: #E3E3E3;
	border: 1px solid #d7d7d7;

	/* Border-radius not implemented yet */
	-moz-border-radius: 11px;
	-webkit-border-radius: 11px;
}
</pre>
<p>The weird value &#8220;2n+1&#8243; is actually pretty simple if you understand what it stands for:</p>
<ul>
<li>2n selects every second item. If you wrote 3n it would select every third item, 4n every fourth item, and so on.</li>
<li>The +1 tells the browser to start at element 1. If you are familiar with programming you probably know that all arrays start at 0, and this is also true here. This means that element 1 is actually the second element in the series.</li>
</ul>
<p>Alternatively, you could simply write:</p>
<pre name="code" class="css">
section#comments article:nth-child(odd) { ... }
</pre>
<p>Since the standard includes the two most used values as shorthand, odd and even. The rest of the comment styling should be simple to understand with your new knowledge.</p>
<h3>Styling the Comment Form, Footer and Sidebar</h3>
<p>A couple of CSS 3 techniques are reused in the styling of the comment form, footer and sidebar. In the comment form and the footer I&#8217;ve used the same type of table layout technique used in the main layout. In the sidebar border-radius is used to add rounded corners to the different sections.</p>
<h3>The Final Design</h3>
<p><a href="http://nettuts.s3.amazonaws.com/373_html5/final/index.html">See the final design</a> with all styling applied.</p>
<h3>Compatibility</h3>
<p>The page renders correctly in Safari 4 and newer webkit-based browsers, as it is the only rendering engine that supports all of the CSS 3 techniques we have used. Firefox 3 has some problems applying rounded corners to our flower image and it doesn&#8217;t support background-size, but besides that the layout works. I&#8217;ve chosen to ignore Internet Explorer as it <a href="http://remysharp.com/2009/01/07/html5-enabling-script/">requires a bit of hacking</a> to get HTML 5 to work. You could also define some more rules and get everything working across major browsers, but all of this is outside the scope of the tutorial.</p>
<h3>Conclusion</h3>
<p>When HTML 5 and CSS 3 are one day implemented in all browsers it will be a lot easier to build websites. We&#8217;ll finally be able to stop using floats for layout (which they were never meant to be used for), and we will spend considerably less time writing javascript to scale our background images or zebra-stripe our tables. Hopefully we will use all this extra time to study some long-neglected areas of web design, like <a href="http://www.youtube.com/watch?v=BTHvs3V8DBA">front end optimization</a> and <a href="http://psd.tutsplus.com/articles/9-information-design-tips-to-make-you-a-better-web-designer/">proper information architecture</a>.</p>
<ul class="webroundup">
<li>Follow us on <a href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/pyyLIAukMLzqcl8Mc3z47zAa0kQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/pyyLIAukMLzqcl8Mc3z47zAa0kQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/pyyLIAukMLzqcl8Mc3z47zAa0kQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/pyyLIAukMLzqcl8Mc3z47zAa0kQ/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=6Ct44CRbhpk:aQL7lSqACeA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=6Ct44CRbhpk:aQL7lSqACeA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=6Ct44CRbhpk:aQL7lSqACeA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=6Ct44CRbhpk:aQL7lSqACeA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=6Ct44CRbhpk:aQL7lSqACeA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=6Ct44CRbhpk:aQL7lSqACeA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=6Ct44CRbhpk:aQL7lSqACeA:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=6Ct44CRbhpk:aQL7lSqACeA:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/6Ct44CRbhpk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/tutorials/html-css-techniques/html-5-and-css-3-the-techniques-youll-soon-be-using/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/tutorials/html-css-techniques/html-5-and-css-3-the-techniques-youll-soon-be-using/</feedburner:origLink></item>
		<item>
		<title>CSS Fundamentals: Containing Children</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/_OMpK62En5Q/</link>
		<comments>http://net.tutsplus.com/tutorials/html-css-techniques/css-fudamentals-containing-children/#comments</comments>
		<pubDate>Fri, 03 Jul 2009 15:50:50 +0000</pubDate>
		<dc:creator>Jeffrey Way</dc:creator>
		
		<category><![CDATA[HTML & CSS]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5664</guid>
		<description><![CDATA[<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/200x200.jpg" alt="CSS Fudamentals: Containing Children" />]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;ve received multiple requests for simpler CSS tutorials that teach the tricky fundamentals. This will serve as the first entry in a series that will receive new additions sporadically each month. Today, we&#8217;ll be reviewing the overflow: hidden, and clearfix tricks to force a parent div to contains its children.
</p>
<p><span id="more-5664"></span></p>
<h3>The Overflow: Hidden Trick</h3>
<p>
Have you ever noticed that when you float all of the children elements within a div, the parent takes up zero space? For example, in your code editor, adding the following within the body tag.
</p>
<pre name="code" class="html">
&lt;div id="container">
  &lt;div id="main">

  &lt;/div>
  &lt;div id="sidebar">

  &lt;/div>
&lt;/div>
</pre>
<p>Now, let&#8217;s add a bit of CSS to simulate a typical website. </p>
<pre name="code" class="css">
#container {
	background: red;
	width: 800px;
	padding-bottom: 2em; }

#main {
	background: green;
	height: 500px;
	width: 600px;
	float: right; }

#sidebar {
	background: blue;
	height: 500px;
	width: 200px;
	float: left; }
</pre>
<p>Above, we&#8217;re simply setting background colors and floating the sidebar and main divs to the left and right, respectively. Note the &#8220;padding-bottom: 2em;&#8221;. This should allow us to see the red background at the very bottom, right? View the page in your browser, and you&#8217;ll see:
 </p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/noOverflow.png" alt="No Overflow Applied" />
</div>
<p>Where did the red background go? Why isn&#8217;t it displaying?  </p>
<h3>The Solution</h3>
<p>
When you float all of the children, the parent essentially takes up no space. To better illustrate this fact, let&#8217;s set an arbitrary height of 50px to the container, and then reduce the opacity of the children divs so that we can see the red background beneath.
</p>
<pre name="code" class="css">
#container {
  .. other styles
  height: 50px; }

#main, #sidebar {
  opacity: .5; }
</pre>
<p>Refresh your browser, and you&#8217;ll see: </p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/notContaining.png" alt="Not Contained" />
</div>
<p>How odd. We&#8217;ve specified a height of 50px for our container div, yet the main and sidebar divs blatantly <em>overflow</em> its boundaries, like spoiled bratty divs. </p>
<p>
Return to your stylesheet, and apply one style:
</p>
<pre name="code" class="css">
#container {
  ...other styles
  overflow: hidden;
}
</pre>
<p>After another refresh, we see: </p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/overflowAndHeightApplied.png" alt="Not Contained" />
</div>
<p>
Well that partially helps. Now, we don&#8217;t have to worry about the pubescent children disobeying their parent. Having said that, this really doesn&#8217;t help our situation.
</p>
<blockquote>
<p>&#8220;Try to avoid specifying heights as much as possible. There&#8217;s usually a smarter method.</p>
</blockquote>
<p>
The solution is to rip out the height property from our container. <strong>Remove</strong> the following property.
</p>
<pre name="code" class="css">
#container {
  ...other styles
  height: 50px; /* Remove this */
}
</pre>
<p>One last refresh, and our problem seems to be fixed. </p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/overflowAppled.png" alt="Overflow Applied" /></p>
<div><em>You can also remove the opacity properties. They were just for demonstration purposes.</em></div>
</div>
<h3>The Rub</h3>
<p>
The method demonstrated above will work in most cases. However, let&#8217;s introduce another variable. What if we want to position an image on the border of our container, so that it overlaps. You&#8217;ve seen this effect many times. For the sake of the example, we&#8217;ll just use an image of a circle with a transparent background. On a real site, this might represent a &#8220;Buy Now&#8221; or &#8220;Sign Up&#8221; button &#8212; something cheesy like that.
</p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/circle.png" alt="Circle" />
</div>
<h3>Positioning the Circle</h3>
<p>Using CSS, let&#8217;s position the image in the top right portion of our &#8220;website&#8221;, overlapping the edges. This is what we want:
</p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/breakingBoundaries.png" alt="Breaking Boundaries" />
</div>
<p>First, we reference the image within our HTML. </p>
<pre name="code" class="html">
&lt;div id="container">
  &lt;img src="circle.png" alt="Buy Now" />
  ...rest of html
</pre>
<p>Next, return to your stylesheet, and add the following styles. </p>
<pre name="code" class="css">
img {
	position: absolute;
	right: -100px;
	top: 20px; }
</pre>
<h3>Positioning Context</h3>
<p>One might think that this will place the image just over the right edge of the container div. However, he&#8217;d be wrong. </p>
<blockquote>
<p>Because we have not set a positioning context, the window will be used instead.</p>
</blockquote>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/positioningContext.png" alt="No positioning context set" />
</div>
<p>Obviously, this is not what we want. To apply a positioning context to our container div, simply add &#8220;position: relative;&#8221; to #container. Once we&#8217;ve done so, the image will no longer use the window as a reference. </p>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/lostHalf.png" alt="Lost Half" />
</div>
<h3>What&#8217;s the Problem Now?</h3>
<p>But now, we have a new problem! Because we set overflow:hidden to our container div, we&#8217;ve somewhat shot ourselves in the foot. How do we break boundaries and take names if overflow is set to hidden? Should we simply accept that this particular website won&#8217;t be taking names today? Absolutely not. In these cases, it&#8217;s worth using a different method. </p>
<h3>The Clearfix Trick</h3>
<p>
With this method, we&#8217;ll use CSS to add content after our container div. This created content will then clear our div, thus forcing it to contain its children. Now obviously we don&#8217;t want to see this content, so we need to be sure to hide it from the viewer.
</p>
<p>
Return to your stylesheet, remove &#8220;overflow: hidden;&#8221; from your container div, and add the following:
</p>
<pre name="code" class="css">
#container {
	... other styles
	_height: 1%; }

#container:after {
	content: ".";
	visibility: hidden;
	display: block;
	clear: both;
	height: 0;
    font-size: 0; }
</pre>
<p>This might appear complicated, but I assure you that it&#8217;s quite simple. </p>
<ul>
<li><strong>_height:</strong> Triggers &#8220;haslayout&#8221; in Internet Explorer, by using the underscore trick to target IE6 directly.
<li><strong>content: </strong> After the container div, append a period.</li>
<li><strong>visibility: </strong> We don&#8217;t want to see the period, so hide it from the page. (Equal to setting opacity: 0;)</li>
<li><strong>display: </strong> Forces the period to display as a block-level, rather than inline.</li>
<li><strong>clear: </strong> The important property. This clears the main and sidebar divs. This is the same as adding an unsemantic &lt;div style=&#8221;clear: both;&#8221;> to our page.</li>
<li><strong>height: </strong>Don&#8217;t take up any space. </li>
<li><strong>font-size: </strong>Just a precaution for Firefox. This browser sometimes adds a bit of space after our parent element. Setting the font-size to zero fixes this.
</ul>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/371_cssBestPractices/perfect.png" alt="Perfect" />
</div>
<h3>Conclusion</h3>
<p>
Though the overflow:hidden trick is preferable, it&#8217;s not always ideal. You need to use the best solution for the task at hand. The important thing is to learn each method, so that you have the tools to solve the puzzle.
</p>
<ul class="webroundup">
<li>Follow us on <a href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/Ixzb5Qo_gBG2DoMu02AJFN0LBxQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/Ixzb5Qo_gBG2DoMu02AJFN0LBxQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/Ixzb5Qo_gBG2DoMu02AJFN0LBxQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/Ixzb5Qo_gBG2DoMu02AJFN0LBxQ/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=_OMpK62En5Q:xOmG5Z2q16c:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=_OMpK62En5Q:xOmG5Z2q16c:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=_OMpK62En5Q:xOmG5Z2q16c:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=_OMpK62En5Q:xOmG5Z2q16c:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=_OMpK62En5Q:xOmG5Z2q16c:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=_OMpK62En5Q:xOmG5Z2q16c:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=_OMpK62En5Q:xOmG5Z2q16c:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=_OMpK62En5Q:xOmG5Z2q16c:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/_OMpK62En5Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/tutorials/html-css-techniques/css-fudamentals-containing-children/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/tutorials/html-css-techniques/css-fudamentals-containing-children/</feedburner:origLink></item>
		<item>
		<title>Easy E-Commerce With Magento</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/lxk0QaksxFQ/</link>
		<comments>http://net.tutsplus.com/videos/screencasts/easy-e-commerce-with-magento/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 18:03:42 +0000</pubDate>
		<dc:creator>Ed Baxter</dc:creator>
		
		<category><![CDATA[Screencasts]]></category>

		<category><![CDATA[e-commerce]]></category>

		<category><![CDATA[ecommerce]]></category>

		<category><![CDATA[magento]]></category>

		<category><![CDATA[screencast]]></category>

		<category><![CDATA[video tutorial]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5650</guid>
		<description><![CDATA[<img src="http://nettuts.s3.amazonaws.com/370_magento/200x200.jpg" alt="Getting Started With Magento" />]]></description>
			<content:encoded><![CDATA[<p>Hundreds of ecommerce systems exist, but very few can match the power of Magento. In this <strong>screencast</strong>, I&#8217;ll demonstrate how to download and install Magento to a local host, configure some of the site options, and create simple and configurable products and categories for our test e-commerce site.
</p>
<p><span id="more-5650"></span></p>
<h3>Screencast</h3>
<div class="tutorial_image">
<embed src="http://blip.tv/play/AYGL4DsA" type="application/x-shockwave-flash" width=590" height="443" allowscriptaccess="always" allowfullscreen="true"></embed>
</div>
<h3>Why Use Magento?</h3>
<p>Well there are quite a few very good reasons to use Magento: </p>
<ul>
<li>A Simple Intuitive Interface</li>
<li>Easy To Download, Install &amp; Maintain</li>
<li>Built on current technologies unlike other systems.</li>
<li>Multiple Site Functionality</li>
<li>And best of all&#8230;It&#8217;s free and open source!</li>
</ul>
<h3>Preparation</h3>
<p>As with all successful things in life, preparation is key! Before we can install Magento we must set up a database on our server. Using phpmyadmin we create a new database called &#8220;magento&#8221;. We will use this later when we come to install Magento. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/create-database.jpg" border="0" /></div>
<h3>Downloading/Installing Magento</h3>
<p>Once our database has been set up on our server the next step is to download Magento itself. To do that we need to go to the <a href="http://www.magentocommerce.com/download">download page</a> on the Magento website. For this tutorial we will be downloading the Full Release in ZIP format. Once you have it downloaded unzip it to the folder of your choice. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/download-page.jpg" border="0" /></div>
<p>Now that we have the files on our server it’s time to install Magento, to do this we go to http://localhost/magento (or whichever folder your using) in your web browser. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/toc-agree.jpg" border="0" /></div>
<p>Accept the TOC&#8217;s and continue onto the next page.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/localization-settings.jpg" border="0" /></div>
<p>Pick the settings that apply to you and click continue. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/database-config.jpg" border="0" /></div>
<p>Going well so far&#8230;Now fill in the database connection settings. <strong>Make sure that you hit Use Web Server (Apache) Rewrites for added SEO friendliness</strong> and if you want to change the default access address for your backend from /admin edit the Admin Path field. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/user-details.jpg" border="0" /></div>
<p>Fill in the login details you&#8217;d like to use for your account and enter an custom encryption key if you like, otherwise leave it blank and Magento will make one for you. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/all-set.jpg" border="0" /></div>
<p>Great, now Magento has been installed on your server, if you have installed locally there is one last step you need to take before you can login&#8230;</p>
<p>In your Magento folder go to app/code/core/Mage/Core/Model/Session/Abstract/Varien.php</p>
<p>Find the session_set_cookie_params code block (Line 78) and replace it with this code:</p>
<pre name="code" class="php">
		session_set_cookie_params(
            $this->getCookie()->getLifetime(),
            $this->getCookie()->getPath()
            //$this->getCookie()->getDomain(),
            //$this->getCookie()->isSecure(),
            //$this->getCookie()->getHttponly()
        );
</pre>
<p><strong>On a proper webhost you do not need to do this!</strong> However as we are working on localhost we need to do this to address an cookie issue.</p>
<h3>Tax Rules</h3>
<p>To set up our different levels of tax we need to go to the Manage Tax Zones &amp; Rates tab under Sales &#038;raquo Tax. If the rule for your state doesn&#8217;t exist or has been changed recently then hit the &#8220;Add New Tax Rate&#8221;. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/tax-one.jpg" border="0" /></div>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/tax-two.jpg" border="0" /></div>
<p>Save your new tax rule and you are good to go!</p>
<h3>Categories</h3>
<p>To create a new category we need to go to the Catalog tab on the navigation and select Manage Categories. From there we can manage and add new categories.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/categories-one.jpg" border="0" /></div>
<p>To create our new category we need to click <strong>Add Subcategory</strong> and fill in the details like the picture below, making sure to change Is Active to Yes. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/categories-two.jpg" border="0" /></div>
<h3>Products</h3>
<p>Products are key to a site but in Magento there was multiple product types as shown below&#8230;To create a new product we need to <strong>Catalog tab</strong> on the navigation and select <strong>Manage Products</strong>. And finally click <strong>Add Product</strong></p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/new-product-one.jpg" border="0" /></div>
<h4>Simple Products</h4>
<p>These are the products that have no options, such as DVD. To create our Simple product select Default for the attribute set and Simple Product for the Product Type and click Continue.</p>
<h4>General Tab</h4>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/simple-product-one.jpg" border="0" /></div>
<ol>
<li>Name: The name of our new product</li>
<li>Description: The main body description of the product; the place to really sell the product and all of its features!</li>
<li>Short Description: The quick overview that appears just below the price on the product page; the place to grab the attention of buyers</li>
<li>SKU: The stock code for the product</li>
<li>Weight: The weight of the product. This can be kilos, tonnes or whatever you want as long as you keep uniformity across all your products</li>
<li>Manufacturer: Blank by default but manufacturers can be added through the Manage Attributes Tab. </li>
<li>Colour: Blank by default but again like the manufactures can be added through the Manage Attributes Tab</li>
<li>Set Product As New From Date: Sets the product to new from the date you enter.</li>
<li>Set Product as New to Date: Sets when the product ends being new.</li>
<li>Status: If the product is Enabled and showing on the website or if it&#8217;s disabled. </li>
<li>URL key: The custom option for how the URL for your product is written. </li>
<li>Visibility: Where the product can be found by your visitors;
<ul>
<li>Nowhere: The product does not appear on the website.</li>
<li>Catalog: The product will appear on the website but not in search results.</li>
<li>Search: The product will not appear on the website but will appear in search results.</li>
<li>Catalog, Search: The product will appear on the website and in search results.</li>
</ul>
</li>
<li>Allow Gift Message:
<ul>
<li>Yes: Allows a gift message</li>
<li>No: Doesn&#8217;t allow a gift message</li>
<li>Config: Use the site&#8217;s configuration</li>
</ul>
</li>
</ol>
<h4>Price Tab</h4>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/simple-product-two.jpg" border="0" /></div>
<ol>
<li>Price: The price of our product</li>
<li>Special Price: Offers on products for limited times.</li>
<li>Special Price From Date: The date in which the special price starts.</li>
<li>Special Price To Date: The date in which the special price ends.</li>
<li>Cost: The cost of the product.</li>
<li>Tax Class: If your product requires Tax added then Taxable Goods must be selected.</li>
<li>Tier Price: Allows for bulk discounts to be set up. Click <strong>Add Tier</strong> to add quantity discounts.</li>
<li>Google Checkout: Can visitors buy this product using Google Checkout.</li>
</ol>
<h4>Meta Information Tab</h4>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/simple-product-three.jpg" border="0" /></div>
<ol>
<li>Meta Title: Information that appears in the &lt;title&gt; tag.</li>
<li>Meta Keywords: keywords that apply to your product.</li>
<li>Meta Description: A short description of your product that appears on Search Engine Result Pages.</li>
</ol>
<h4>Images Tab</h4>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/simple-product-image-upload.jpg" border="0" /></div>
<p>Images are a key part of your product and the better quality you can get the more chance you have of making a sale, Magento allows for multiple images to be uploaded and specific images to be uploaded for the Base Image, the Small Image and the Thumbnail, as well as allowing for a label. If you want to remove an image simply click the Exclude to hide or the Remove to delete checkbox(s).</p>
<ul>
<li>Base Image: The main image that appears on the product page.</li>
<li>Small Image: The image that appears in the categories/search view.</li>
<li>Thumbnail: The thumbnail of the product.</li>
</ul>
<h4>Design Tab</h4>
<p>Unless you are using a template for your Magento store it&#8217;s best to give this one a miss, but for anyone who is curious the Design tab allows you to use themes that you have set up and allows you to choose active to and from dates as well as changing the page layout into different column blocks and so on.</p>
<h4>Inventory Tab</h4>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/simple-product-inventory.jpg" border="0" /></div>
<ol>
<li>Manage Stock: If you&#8217;d like to track and manage stock levels then leave this set to Yes</li>
<li>Qty: The amount of product you have.</li>
<li>Stock Availability: If the product is in stock or not. Setting this to Out of Stock will not hide the product on the website!</li>
</ol>
<p>The other options are best left to the site configuration however are all pretty self explanatory if you wish to set them to your needs. </p>
<h4>Categories Tab</h4>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/simple-product-categories.jpg" border="0" /></div>
<p>Your product can appear in multiple categories; simply click the checkbox of the category you want it to appear in!</p>
<h4>Related Products / Up-sells / Cross-sells</h4>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/simple-product-related-products.jpg" border="0" /></div>
<p>With related products, up-sells and cross-sells the interface to add is same, to add a product simply select a field you wish to search by and click the search button, a list of products matching your criteria will appear. Click the checkbox next to the product and it will appear as a related product/up-sell or cross-sell as applicable.</p>
<h4>Product Reviews / Product Tags / Customers Tagged Product</h4>
<p>These are all added by users and can viewed from the tabs. </p>
<h4>Custom Options</h4>
<p>These are custom options that you can add to your product. To add a custom option click <strong>Add New Option</strong> and fill in the details.</p>
<h3>Managing Attributes &amp; Attribute Sets</h3>
<p>Attributes are the options that make up your products, for example colour, weight and so on. Attribute sets are sets of attributes that make a whole product and allow us to make configurable products.</p>
<h4>Attributes</h4>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/attributes-one.jpg" border="0" /></div>
<p>To create a new attribute/view our current attributes we need to go to the Catalog tab on the navigation and select Attributes and then Manage Attributes. To view a attribute simply click on the row, to create a new attribute click the <strong>Add New Attribute</strong> Tab.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/attributes-new.jpg" border="0" /></div>
<h4>Properties Tab</h4>
<p>It&#8217;s best to use an convention when you are naming your attributes, as your list grows it will make it easier to find what you are looking for. I like to use <i>options_option_product</i> which for this product would be options_colour_nettuts_shirt. We must set our scope to global and Catalog Input Type to Dropdown in order to create our configurable product(s). We are only applying our Attribute to Simple Products and Configurable Products. In order to use this attribute in our configurable products we must choose Yes on the <strong>Use To Create Configurable Product</strong> field. We must also select Yes on the Visible on Product View Page on Front-end field in order to make the attribute visible. </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/attributes-labels.jpg" border="0" /></div>
<h4>Manage Label / Options Tab</h4>
<p>Next we need to set up the options for our user to select from when choosing there product. In our example we are using Colour as our product option.</p>
<p>The title is what the visitor will see above the dropdown, with Magento we can define what the admin sees and what the user sees making it easier to track options with additional information, in the example we have called our Title, Colour. If we leave the Default Store View blank it will copy what we have entered into Admin.</p>
<p>To add the options for our product click the Add Option button for the number of options you require, in our example 3. Like the title if we leave the Default Store View blank it will copy what we have entered into Admin but we can use the Admin field to add more information, making it easy to fulfill orders for example. We use position to order our options and the Is Default radio box to define which option is default. We can easily delete any option using the button to the right. Once we have all the options we want click Save to return to the attributes page.</p>
<h4>Attribute Sets</h4>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/attributes-two.jpg" border="0" /></div>
<p>Next we need to set up our Attribute Set in order to create our configurable product. We navigate to the Catalog tab on the navigation and select Attributes and then Manage Attribute Sets. Like the Attributes page we have a list of our Current Attribute Sets; Default should only be appearing. Click Add New Set.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/attribute-set-one.jpg" border="0" /></div>
<p>Again like our Attribute we should use a convention to name our Attribute Set&#8230;so matching our Attribute; options_size_tshirts. Since we have no other Sets we are going to base the new one on Default.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/attribute-set-two.jpg" border="0" /></div>
<p>To include our Attribute into our Set we simply need to click and drop it into the General group from the right hand list. Click save and our set is complete. Going well so far&#8230;</p>
<h3>Creating A Configurable Product</h3>
<p>Creating a configurable product is very similar to creating a Simple Product. To start we create a new product. But we need to change the Attribute Set to the one we just created and the product type to Configurable Product and click continue.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/config-product-one.jpg" border="0" /></div>
<p>Next we need to pick the Attributes we would like to use in our product. Only attributes with a scope of Global, type of dropdown and the option to create a configurable product set to yes can be used.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/config-product-two.jpg" border="0" /></div>
<p>The only tabs that change are the Inventory tab and an new tab has been added called Associated Products which is where we will add our options. Once we have filled in all our details we need to save and continue edit before we can begin to add our Associated Products. Unlike some other ecommerce systems Magento creates simple products that are hidden in order to create a configurable product.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/config-product-three.jpg" border="0" /></div>
<p>To create the options we are going to use the &#8220;Quick simple product creation&#8221; tool to make our Simple Product options. For the name and SKU fields you can let Magento auto generate these but for added control I suggest that you fill these in yourself. In the example we are creating a green shirt option. We have filled in the Name, SKU, Weight and have set the product to Enabled. However <strong>we must set the visibility of our product to nowhere</strong>. From the drop-down we select the attribute option we are creating for and set the price. For the default option we don&#8217;t enter a value and it will use the price we set on our configurable product but for the other options we enter the difference between the configurable product and the option. So if the Green top is $15 and our configurable product is $20 then we have to enter -5.00 as our price. We then need to set the Qty for the option and the Stock Availability to In Stock and click Quick Create. We repeat this process until we have added all of our options and click save. Our configurable product is now complete. If we view our products page we can see that Magento has created the options as simple products for us that have been hidden. Making tracking stock much easier!</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/370_magento/config-product-four.jpg" border="0" /></div>
<h3>Congratulations</h3>
<p>Well done, you have just downloaded and installed Magento to your localhost, you have created a simple product, a custom attribute and attribute set, a configurable product using your custom attribute and a category. I hope that you have learned some of the basics of Magento and I wish you all the best during your endeavors. If you have any questions please leave a comment below and i&#8217;ll try my best to help you out!</p>
<p>If you a real go getter and would like to get into some of the more advanced topics or would like to learn more than I suggest that you check out the <a href="http://www.magentocommerce.com/knowledge-base">Knowledge Base</a> on the Magento website as well as <a href="http://www.magentocommerce.com/design_guide">Designers Guide</a> if you’re interested in customizing Magento more.</p>
<ul class="webroundup">
<li>Follow us on <a href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/i3gHN1fvaYGV2bkqnGrWAmEb4TQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/i3gHN1fvaYGV2bkqnGrWAmEb4TQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/i3gHN1fvaYGV2bkqnGrWAmEb4TQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/i3gHN1fvaYGV2bkqnGrWAmEb4TQ/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=lxk0QaksxFQ:fYkB5qW2UwE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=lxk0QaksxFQ:fYkB5qW2UwE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=lxk0QaksxFQ:fYkB5qW2UwE:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=lxk0QaksxFQ:fYkB5qW2UwE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=lxk0QaksxFQ:fYkB5qW2UwE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=lxk0QaksxFQ:fYkB5qW2UwE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=lxk0QaksxFQ:fYkB5qW2UwE:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=lxk0QaksxFQ:fYkB5qW2UwE:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/lxk0QaksxFQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/videos/screencasts/easy-e-commerce-with-magento/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/videos/screencasts/easy-e-commerce-with-magento/</feedburner:origLink></item>
		<item>
		<title>Create an s3Slider-like jQuery Plugin: New Plus Tutorial</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/iwedPdDWz1Y/</link>
		<comments>http://net.tutsplus.com/articles/news/create-an-s3slider-like-jquery-plugin-new-plus-tutorial/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 05:00:30 +0000</pubDate>
		<dc:creator>Boban Karišik</dc:creator>
		
		<category><![CDATA[News]]></category>

		<category><![CDATA[jQuery plugin]]></category>

		<category><![CDATA[plus tutorial]]></category>

		<category><![CDATA[s3slider]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5637</guid>
		<description><![CDATA[<img src="http://nettutsplus.s3.amazonaws.com/19_sliderPlugin/200x200.jpg" alt="Create an s3slider-like jQuery Plugin: New Plus Tutorial" />]]></description>
			<content:encoded><![CDATA[<p>
In this week&#8217;s <a href="http://www.tutsplus.com">Plus</a> video tutorial, the creator of the extremely popular <a href="http://www.google.com/url?sa=t&#038;source=web&#038;ct=res&#038;cd=1&#038;url=http%3A%2F%2Fwww.serie3.info%2Fs3slider%2F&#038;ei=HYlLStjHL8a7lAf8i7gO&#038;usg=AFQjCNEYGYNHjrmcD0DME8tyHcIZHE9-bA&#038;sig2=OmHmpb5FxRCcga-NrXZDCg">s3Slider</a> plugin will show you how to build a similar &#8220;slideshow&#8221; component using jQuery. What better way to learn how to mimic your favorite plugins than to learn from the creators themselves? This isn&#8217;t one you should miss! <a href="http://net.tutsplus.com/about/join-plus/">Become a Plus member today!</a>
</p>
<p><span id="more-5637"></span></p>
<div class="tutorial_image">
<a href="http://nettuts.s3.amazonaws.com/367_sliderPlustut/example/index.html"><img src="http://nettuts.com/wp-content/themes/nettuts/site_images/button_demo_nm.jpg"></a>
</div>
<h3>Join Tuts Plus</h3>
<div class="tutorial_image"><img src="http://miscfiles.s3.amazonaws.com/banners/nettuts_468x60.jpg" border=0 alt="NETTUTS+ Screencasts and Bonus Tutorials" width=468 height=60></div>
<p>
For those unfamiliar, the family of TUTS sites runs a premium membership service called <a href="http://www.tutsplus.com">&#8220;TUTSPLUS&#8221;</a>. For $9 per month, you gain access to exclusive premium tutorials, screencasts, and freebies at <a href="http://net.tutsplus.com">nettuts+</a>, <a href="psd.tutsplus.com">psdtuts+</a>, and <a href="vector.tutsplus.com">vectortuts+!</a> For the price of a pizza, you&#8217;ll learn from some of the best minds in the business. <a href="http://net.tutsplus.com/about/join-plus/">Join today!</a> </p>
<ul class="webroundup">
<li>Subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/tw0MTJl3osLi5DBSc7NRrXVH6fg/0/da"><img src="http://feedads.g.doubleclick.net/~a/tw0MTJl3osLi5DBSc7NRrXVH6fg/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/tw0MTJl3osLi5DBSc7NRrXVH6fg/1/da"><img src="http://feedads.g.doubleclick.net/~a/tw0MTJl3osLi5DBSc7NRrXVH6fg/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=iwedPdDWz1Y:wJycOYSYqV8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=iwedPdDWz1Y:wJycOYSYqV8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=iwedPdDWz1Y:wJycOYSYqV8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=iwedPdDWz1Y:wJycOYSYqV8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=iwedPdDWz1Y:wJycOYSYqV8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=iwedPdDWz1Y:wJycOYSYqV8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=iwedPdDWz1Y:wJycOYSYqV8:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=iwedPdDWz1Y:wJycOYSYqV8:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/iwedPdDWz1Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/articles/news/create-an-s3slider-like-jquery-plugin-new-plus-tutorial/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/articles/news/create-an-s3slider-like-jquery-plugin-new-plus-tutorial/</feedburner:origLink></item>
		<item>
		<title>10 Tips for New iPhone Developers</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/XcRDmsltSAg/</link>
		<comments>http://net.tutsplus.com/tutorials/other/10-tips-for-new-iphone-developers/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 15:44:40 +0000</pubDate>
		<dc:creator>Paolo Ranoso</dc:creator>
		
		<category><![CDATA[Other]]></category>

		<category><![CDATA[iphone]]></category>

		<category><![CDATA[mobile]]></category>

		<category><![CDATA[mobile development]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5625</guid>
		<description><![CDATA[<img src="http://nettuts.s3.amazonaws.com/366_iphone/200x200.jpg" alt="10 Tips for New iPhone WebApp Developers" />]]></description>
			<content:encoded><![CDATA[<p>Making a webapp for the iPhone is a lot like making a normal web site, but with a few quirks to abide by. In this article, I&#8217;ll give you a wide variety of tips, covering things such as: &#8220;must-haves&#8221;, usability guidelines, testing/debugging, pitfalls, and performance issues. I hope you enjoy it!
</p>
<p><span id="more-5625"></span></p>
<h3>WebApps vs. Native Apps</h3>
<p>Keep in mind that a web application runs in the browser, while a native application is installed on the iPhone.<br />
So, if you want to make something like a high-performance, fast-responsive, action-packed game with awesome graphics, then you&#8217;re probably better<br />
off just learning Objective-C and making a native app.  However, if you don&#8217;t own a Mac and/or if you are trying to do something a lot simpler, like<br />
making a mobile version of your website or blog, then making a web app might be the faster and more reasonable road to take.
</p>
<p>Still not convinced?  Here are a list of popular sites that are iPhone web apps/websites:</p>
<ul>
<li><a href="http://iphone.facebook.com">iphone.facebook.com</a></li>
<li><a href="http://m.digg.com">m.digg.com</a></li>
<li><a href="http://hotels.com/iphone">hotels.com/iphone</a></li>
<li><a href="http://iphone.fmylife.com/">iphone.fmylife.com</a></li>
<li><a href="http://iphone.coldwellbanker.com/">iphone.coldwellbanker.com</a></li>
</ul>
<p>
The list goes on&#8230;<br />
If you&#8217;re REALLY smart, you&#8217;ll make BOTH a native app(hopefully free) and web app, like most of the sites above did.
</p>
<h3>1:  Viewport, Viewport, Viewport</h3>
<p>I would say this may be the simplest and most important thing for an iPhone web app.  It&#8217;s just one line of code to include within your head tags:</p>
<pre name="code" class="html">
	&lt;!-- add this in your &lt;head&gt; section with your other meta tags--&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;&quot; /&gt;
</pre>
<p>This tells the browser to scale your page in such a way that will make it fit nicely on the iPhone.  Here&#8217;s what each field means:</p>
<ul>
<li><strong>width=device-width</strong><br />This fits the page to the device&#8217;s width.  The iPhone&#8217;s display is 320&#215;480 pixels in portrait mode, and 480&#215;320 pixels in landscape mode, which is why you sometimes see sites use width=320 instead of width=device-width.</li>
<li><strong>initial-scale=1.0</strong><br />This is the scaling when the page first loads up.</li>
<li><strong>maximum-scale=1.0</strong><br />This is the maximum scaling allowed.</li>
<li><strong>user-scalable=0</strong><br />This determines whether the user is allowed to zoom in and out by pinching/double-tapping.  You can also use user-scalable=no and user-scalable=yes instead of 0 and 1.</li>
</ul>
<p>Keep in mind that the viewport IS NOT A WINDOW.  Think of it like a magnifying glass over a page.  You can move the magnifying glass around and zoom in/out.<br />
This is why certain features like fixed positioning don&#8217;t work on the iPhone(at least at the time of this writing).  In <em>Professional iPhone and iPod touch Programming</em>, Richard Wagner explains what a viewport is:
</p>
<blockquote><p>
A viewport is a rectangular area of screen space within which an application is displayed. Traditional<br />
Windows and Mac desktop applications are contained inside their own windows. Web apps are displayed<br />
inside a browser window. A user can manipulate what is seen inside of the viewport by resizing the<br />
window, scrolling its contents, and in many cases, changing the zoom level.
</p></blockquote>
<p>Specifying the viewport is a <strong><em>*must-have*</em></strong> and is the first step into making your web app iPhone-friendly.</p>
<h3>2:  &quot;Hide&quot; the Address Bar!</h3>
<p>The address bar takes up a considerable portion of the already tiny screen we have to work with.  You&#8217;ll want to hide the address bar to display as much information on the screen as you can, so that the user doesn&#8217;t have to flick down.  Consider the picture below.  Is that the whole screen, or is there more information below?</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/366_iphone/images/withaddressbar.jpg" border="0" alt="With the address bar" /><br/>With the address bar</div>
<p>Now let us hide the address bar by adding this single line of javascript code:</p>
<pre name="code" class="js">
//add this in your javascript code to 'hide' the address bar
window.scrollTo(0, 1);
</pre>
<p>This will &quot;hide&quot; the address bar by scrolling down just enough so that you won&#8217;t see it when loading the page. In our picture below, we see that there was more information to be displayed after all!</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/366_iphone/images/noaddressbar.jpg" border="0" alt="Without the address bar" /><br/>Without the address bar</div>
<p>Notice that this only temporarily hides the address bar by just scrolling down a bit upon loading the page.  Permanently hiding the address bar may not be the best idea, but it is possible.  For safety&#8217;s sake, we&#8217;ll leave that outside of the scope of this article.</p>
<h3>3: Test on iPhone AND Browsers</h3>
<p>Although your ultimate goal is to put your web app on the iPhone, testing it on normal browsers can be beneficial!</p>
<p>Remember, since this is a <strong><em>web</em></strong> application, you can test it like one!  That means useful tools like Firebug, Web Developer, and YSlow still work!</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/366_iphone/images/firebugerror.jpg" border="0" alt="Using Firebug to Test/Debug your iPhone web app" /><br/>&quot;A firebug error!? But that&#8217;s impossible&#8230;my code is <strong><em>always</em></strong> perfect!&quot; </div>
<p>NOTE:  You may get errors for certain pieces of code that are legitimate &#8212; iPhone-specific/webkit-specific code mostly.  With that said, don&#8217;t be too dependent on these tools&#8230;they are more of a guide, not an oracle.</p>
<p>Keep in mind also that Firefox may display things differenty than Safari does, and Safari is also different from Mobile Safari.  You&#8217;ll most certainly notice web apps that you develop in <a href="http://developer.apple.com/tools/dashcode/">Dashcode</a> won&#8217;t display properly on Firefox.<br />
 This is why you still need to test on an iPhone.  If you do however, develop in Dashcode, there are testing/debugging features that come with it.</p>
<h3>4: Mimic a Native App if Possible</h3>
<p>From a usability perspective, making your web app look like a native iPhone app is beneficial because users already know how to use an iPhone application, thus there is a <a href="http://en.wikipedia.org/wiki/Transfer_of_training">positive transfer of knowledge</a>.<br />
Besides that, using the buttons, font, lists, etc is also beneficial.  A lot of time and money was put into researching what would be a good design&#8230;Apple must have hired various usability and design experts.<br />
If you mimic a native app, you won&#8217;t have to go through the whole process of designing and creating something that may in the end prove infeasible.
</p>
<p>Take a look at the picture below&#8230;this is the &quot;Groups&quot; menu from the &quot;Contacts&quot; feature.  Can you guess whether this is the real deal(native app), or a fake(webapp mimic)?</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/366_iphone/images/webapp.jpg" border="0" alt="Is this a native app or web app?" /><br/>Native app or web app?</div>
<p>If you guessed that the above pic is a web app, you are correct!  See how closely you can mimic a native app?</p>
<p>If you do not wish to mimic a native iPhone web app, perhaps because your application doesn&#8217;t fit well that way or because you want to maintain your style, then at least follow some basic guidelines:</p>
<ul>
<li>Be consistent (i.e: navigation buttons on each page)</li>
<li>Make buttons large enough to tap (i.e: for fat fingers or the error-prone)</li>
<li>Make things intuitive (i.e: collapsible boxes should have hint&#8230;like a +/- next to it)</li>
</ul>
<h3>5: Use Frameworks, Libraries, and Tools to Save Time</h3>
<p>If you do decide to mimic a native app, then I suggest not starting from scratch.  There are many things out there that can save you a ton of time:</p>
<ul>
<li><strong><a href="http://developer.apple.com/documentation/AppleApplications/Conceptual/Dashcode_UserGuide/Contents/Resources/en.lproj/MakingaWebApp/MakingaWebApp.html"><br />
Dashcode</a></strong><br/>If you have a Mac, this may be the best route to go if you want to whip up something fast.  Dashcode has a parts library(i.e: buttons/frames), a code snippets library, a workflow steps guide, and way more!</li>
<li><strong><a href="http://code.google.com/p/iui/">iUI</a></strong><br/>Created by <a href="http://www.joehewitt.com/">Joe Hewitt</a>, this nice little framework lets you create web apps with simple HTML!  It has a nice slide-effect too.  Performance is FAST and the framework itself is very tiny filesize-wise.</li>
<li><strong><a href="http://iwebkit.net/">iWebkit</a></strong><br/>Just like iUI, you can create your app with simple HTML.  However, this framework has many <a href="http://demo.iwebkit.net/">features</a> that other frameworks might not have.  It also comes with a user guide which clearly explains how to use the features.<br />
What makes this my favorite framework is that it plays nice with other javascript code, so I can customize my web app and do things like make collapsible boxes</li>
</ul>
<p>There are, of course, many other frameworks, libraries, and tools, but as to date, these are my favorite ones.  Have one that you really like?  Write it in the comments below!</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/366_iphone/images/popupfeature.jpg" border="0" alt="iWebkit popup" /><br/><a href="http://iwebkit.net/">iWebkit</a>&#8217;s pop-up feature</div>
<h3>6: Use Lists When Possible</h3>
<p>Lists are a nice quick n&#8217; dirty way of displaying information.  &quot;Contacts&quot; and &quot;Mail&quot; display information in the form of lists.  Lists allow for easy navigation, let you display a lot of items on the tiny screen, and are easy to touch compared to pictures.<br />
They also load pretty fast since they&#8217;re just text.  Lists will almost always be your navigation method of choice, but then again it really depends on what your web app is.</p>
<p>If you do use a list, grouping items by alphabet, relevance, or usage is always a good way to go.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/366_iphone/images/lists.jpg" border="0" alt="An alphabetical list" /><br/>A list with items grouped by alphabet</div>
<h3>7: Minimize Horizontal Navigation</h3>
<p>If possible, minimize the number of screens your users have to navigate to in order to get the information they want.<br />
Having less pages to jump to means less redirecting and unnecessary loading by going backwards and forewards.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/366_iphone/images/manyscreens.jpg" border="0" alt="Many screens" /><br/>Many navigation screens</div>
<p>In the example picture above, we can possibly eliminate the first two screens by automatically getting the date/time and start out with the third screen.<br />
If a user wants to intentionally pick and different day/time, we can have that in the &quot;Change View&quot; menu.
</p>
<h3>8: Make Your App Small and Fast</h3>
<p>Remember that performance is critical in the mobile world, as a user may be on the EDGE network or just have a slow connection.  Give them as little to download as possible!  Just like normal web sites, the same rules of enhancing performance apply.  Instead of<br />
giving you a checklist of everything, I would just recommend that you get both <a href="http://code.google.com/speed/page-speed/">Page Speed</a> and <a href="http://developer.yahoo.com/yslow/">YSlow</a>, as these<br />
give more detailed checklists on beefing up performance than I could ever give.  </p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/366_iphone/images/iuisize.jpg" border="0" alt="iui filesize" /><br/>Not bad for a framework that has a .js file, a .css file, and a bunch of images, huh?</div>
<h3>9: Have a Homescreen Icon</h3>
<p>Make sure to have a nice icon that people can see when they add your web app to their homescreen.  Make a 57&#215;57 PNG file and add the following code to your home page:</p>
<pre name="code" class="html">
	&lt;!-- add this in your &lt;head&gt; section --&gt;
    &lt;link href=&quot;path/to/your/icon.png&quot; rel=&quot;apple-touch-icon&quot; /&gt;
</pre>
<p>Having an icon is a good way to quickly recognize your web app, as well as look professional while having some nice eye-candy.</p>
<h3>10: iPhone &#8216;Simulators&#8217; aren&#8217;t Perfect</h3>
<p>You will notice that iPhone simulators, even the official &quot;Aspen Simulator&quot;, can sometimes yield different results than on the iPhone.  This is true even when making native apps.  This should actually be somewhat expected since the iPhone OS is different from Mac OS and the iPhone architecture is different from a normal computer.  I want people to know about this, because I&#8217;ve had quite a few friends<br />
develop and test mainly on &quot;simulators&quot; only to find out near final production/deployment that their program on the iPhone was buggy, crashed, or simply just didn&#8217;t work.  Please be careful when using a simulator&#8211;they are here for convenience, NOT for iPhone replacement. Remember that since your ultimate goal is to put something on the iPhone, then test on the iPhone.  Since you are making a web app and not a native app, you won&#8217;t need to worry about paying the developer fee or becoming a registered developer with Apple.</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/366_iphone/images/sadface.jpg" border="0" alt="simulator FAIL" /><br/>Simulator FAIL</div>
<h3>Conclusion</h3>
<p>I hope you enjoyed this article!  One of the joys of making a web app is you can develop on any platform!  I tried to keep the tips as cross-platform as possible.  However, although this is true, it still might be the best idea to develop on a Mac.</p>
<p>There are many other important tips that I did not mention here, simply because other people have beaten me to the punch!  If you are really serious about iPhone web app development, go out there and learn more!  There are plenty of resources that <a href="http://www.google.com/">your best friend</a><br />
can give you that I would not know about.</p>
<p>Have any tips of your own?  Want to call me out on tips that are nonsense?  Share your knowledge by writing in the comments below!  I love learning new things and I definitely want to be corrected if I am wrong.</p>
<ul class="webroundup">
<li>Please subscribe to the <a href="http://feedproxy.google.com/themeforest" title="ThemeForest RSS Feed">Theme Forest RSS Feed</a>, and follow us on <a href="http://twitter.com/themeforest">Twitter</a>.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/LS5kMqhAAa-maP4SuCoTGDMCDgY/0/da"><img src="http://feedads.g.doubleclick.net/~a/LS5kMqhAAa-maP4SuCoTGDMCDgY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/LS5kMqhAAa-maP4SuCoTGDMCDgY/1/da"><img src="http://feedads.g.doubleclick.net/~a/LS5kMqhAAa-maP4SuCoTGDMCDgY/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=XcRDmsltSAg:tE1nrcQl6hM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=XcRDmsltSAg:tE1nrcQl6hM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=XcRDmsltSAg:tE1nrcQl6hM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=XcRDmsltSAg:tE1nrcQl6hM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=XcRDmsltSAg:tE1nrcQl6hM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=XcRDmsltSAg:tE1nrcQl6hM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=XcRDmsltSAg:tE1nrcQl6hM:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=XcRDmsltSAg:tE1nrcQl6hM:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/XcRDmsltSAg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/tutorials/other/10-tips-for-new-iphone-developers/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/tutorials/other/10-tips-for-new-iphone-developers/</feedburner:origLink></item>
		<item>
		<title>Turn-By-Turn Directions with the Google Maps API</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/_pakOrUGy18/</link>
		<comments>http://net.tutsplus.com/tutorials/javascript-ajax/turn-by-turn-directions-with-the-google-maps-api/#comments</comments>
		<pubDate>Tue, 30 Jun 2009 15:44:49 +0000</pubDate>
		<dc:creator>Noah Hendrix</dc:creator>
		
		<category><![CDATA[Javascript & AJAX]]></category>

		<category><![CDATA[api]]></category>

		<category><![CDATA[google]]></category>

		<category><![CDATA[google maps]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5620</guid>
		<description><![CDATA[<img src="http://nettuts.s3.amazonaws.com/365_googleMaps/200x200.png" alt="Turn-By-Turn Directions with the Google Maps API" />]]></description>
			<content:encoded><![CDATA[<p>
In this tutorial, we will go through the process of creating a small widget that allows users to retrieve turn-by-turn directions to a specified location. We&#8217;ll be using the Google Maps API, via JavaScript, to provide this rather advanced functionality.
</p>
<p><span id="more-5620"></span></p>
<div class="tutorial_image">
<a href="http://nettuts.s3.amazonaws.com/365_googleMaps/source.zip"><img src="http://nettuts.com/wp-content/themes/nettuts/site_images/button_src_nm.jpg"></a>
</div>
<div class="tutorial_image">
<img src="http://nettuts.s3.amazonaws.com/365_googleMaps/images/5.png" alt="Final Product" />
</div>
<h3>Getting An API Key</h3>
<p>
  The only caveat with using Google Maps is we must <a href="#">apply for an API key</a>, but this is a fairly trivial process if you already have a Google/GMail account. Unfortunately due to the requirements of Google we must develop on the domain that we provide Google, i.e. we can not develop on a local server. Fortunately for us the process will be quick and we won&#8217;t spend a lot of time on the live server. Also, be sure to store you API key in a safe place because I could not find a way to retrieve them once generated, though I guess you could just recreate one.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/365_googleMaps/images/2.png" border="0" /></div>
<h3>The State of Affairs</h3>
<p>
  Before we dive into code let me discuss the reason behind this idea. As most developers I spend a lot of time on the web. One particular subset of websites I visit are local businesses who certainly don&#8217;t have great resources to devote to web design, but hopefully the people that are developing those sites will see articles like this and realize how easy it is to include a full-featured map into any webpage. Almost any website representing a small business has a page dedicated to telling users how to locate their physical location. Often times you get a map with their location pinned on it, which doesn&#8217;t help users who don&#8217;t know the area. In this tutorial we are going to change that and let users enter their address and get turn-by-turn directions to any address we want.
</p>
<h3>Including the Google Maps Javascript Library</h3>
<p>
  Now that the soapbox is out of way lets look into code. The first thing we need to do is include the Javascript library that contains all the Google Maps methods. Google probably generated this code when you created your API key, but that might have pointed to the version 3 API which is still in beta testing. Here is the link to the API version 2 be sure to insert your API key. We are also going to include a file, <strong>application.js</strong> that will hold our custom functions, I stored mine in a directory at the root level called <strong>js</strong>. The following code goes within the head section of your page.
</p>
<pre name="code" class="js">
&lt;script src="http://maps.google.com/?file=api&#038;v=2&#038;key=INSERT_API_KEY_HERE" type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="./js/application.js" type="text/javascript"&gt;&lt;/script&gt;
</pre>
<h3>The HTML Code</h3>
<p>
  In the body section of our page we need some limited markup. I will briefly go over the required bits, and you can look at the source code to see the fluff I included in my demo. The first element is an empty div with an ID of <strong>map_canvas</strong>, this is the placeholder that we point the Google Maps calls to and it will generate all the map markup within that element.
</p>
<pre name="code" class="html">
&lt;div id="map_canvas"&gt;&lt;/div&gt;
</pre>
<p>
  Next I created a div to hold the organization address and the form for the user to enter their address. You can look over this code but it is pretty simple and not very hard to discern it&#8217;s meeting. Be sure to look at my CSS to see how it is styled in my demo.
</p>
<pre name="code" class="html">
&lt;div id="addresses"&gt;
    &lt;div class="address-panel"&gt;
        &lt;h2&gt;Our Address&lt;/h2&gt;
        &lt;address&gt;
          1450 Jayhawk Blvd #223&lt;br /&gt;
          Lawrence, KS&lt;br /&gt;
          66045
        &lt;/address&gt;
    &lt;/div&gt;

    &lt;div class="address-panel"&gt;
        &lt;h2&gt;Your Address&lt;/h2&gt;

        &lt;form action="./index.php" onsubmit="overlayDirections();return false;" method="post"&gt;
            &lt;div&gt;
              &lt;label for="street"&gt;Street Address&lt;/label&gt;
              &lt;input id="street" name="street_address" type="text" /&gt;
            &lt;/div&gt;
            &lt;div&gt;
              &lt;div class="address-form-column"&gt;
                &lt;label for="city"&gt;City&lt;/label&gt;
                &lt;input id="city" name="city" type="text" /&gt;
              &lt;/div&gt;

              &lt;div class="address-form-column"&gt;
                &lt;label for="state"&gt;State&lt;/label&gt;
                &lt;select id="state" name="state"&gt;
                  &lt;option value="AL"&gt;Alabama&lt;/option&gt;
                  &lt;option value="AK"&gt;Alaska&lt;/option&gt;
                  &lt;option value="AZ"&gt;Arizona&lt;/option&gt;
                  &lt;option value="AR"&gt;Arkansas&lt;/option&gt;
                  &lt;option value="CA"&gt;California&lt;/option&gt;
                  &lt;option value="CO"&gt;Colorado&lt;/option&gt;
                  ...
                &lt;/select&gt;
              &lt;/div&gt;

              &lt;div class="address-form-column"&gt;
                &lt;label for="zip"&gt;Zip Code&lt;/label&gt;
                &lt;input id="zip" name="zip_code" type="text" maxlength="5" size="5" /&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class="button"&gt;
              &lt;input name="submit" type="submit" value="Get Directions" /&gt;
            &lt;/div&gt;
        &lt;/form&gt;
    &lt;/div&gt;
&lt;/div&gt;
</pre>
<p>
  Notice that we are submitting this page to itself this is so we can process the page using PHP if the user has JS disabled. If they have JS enabled we want to execute a function, <strong>overlayDirections()</strong> which we will take a look at a little later. The bulk of this code goes to the select box that lets the user pick their state, I&#8217;ve condensed it for the sake of those printing this article, but you can grab the full code from the download. Other interesting notes is we set the <strong>size</strong> and <strong>maxlength</strong> of the zip code text field to 5. The final thing to take note is that we have assigned ids and names to all of the form elements.
</p>
<h3>Bootstrapping and Declaring Variables</h3>
<p>
  Alright now we can move into the meat of this tutorial, the JavaScript code. Nearly all the calls we are going to make come from the Google Maps API that we referenced earlier. Google provides excellent documentation and example code on their website so be sure to <a href="http://code.google.com/apis/maps/documentation/index.html">check it out</a>. I&#8217;ll try to link to relevant pages as I use them.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/365_googleMaps/images/1.png" border="0" /></div>
<p>
  The first thing is while we have our HTML page open lets bootstrap the initialize function by setting <strong>onload</strong> attribute. <strong>Note</strong>: this could be done in jQuery using the <strong>$(document).ready()</strong> function.
</p>
<pre name="code" class="html">
&lt;body onload="initialize()"&gt;
</pre>
<p>
  Now we are going to move in to the <strong>js/appication.js</strong> file. The very first thing we need to do is set some variables. Some code evangelist will probably hunt me down for declaring global variables, but I believe in this case we should be okay. I&#8217;ll give you the code and then explain how we will use each one.
</p>
<pre name="code" class="js">
var gdir, fromAddress, toAddress;
</pre>
<ul>
<li><strong>gdir</strong>: holds the <a href="http://code.google.com/apis/maps/documentation/reference.html#GDirections">GDirections</a> object used to obtain driving directions results and display them on a map and/or a text panel.</li>
<li><strong>fromAddress</strong>: a string that holds the full address of the user.</li>
<li><strong>toAddress</strong>: a string that holds the business/organization address</li>
</ul>
<h3>The initialize() Function</h3>
<p>
  The initialize() function we called earlier will be used to create the Map on the page and place a custom marker of our location.
</p>
<pre name="code" class="js">
/*
**
* Bootstrap function to setup map and apply
* custom company marker
*/
function initialize() {
  if (GBrowserIsCompatible()) {
    //settings
    var companyMarkerImage= "./images/jayhawk.gif";
    var companyLatLng     = new GLatLng(38.957101, -95.251469);
    var companyMarkerSize = new GSize(55, 52); //width, height

    toAddress = "1450 Jayhawk Blvd #223 Lawrence, KS 66045";

    var defaultZoomLevel  = 13;
    //end settings

    //setup elements
    map   = new GMap2(document.getElementById("map_canvas"));
    gdir  = new GDirections(map, document.getElementById("directions"));

    //error handler
    GEvent.addListener(gdir, "error", handleErrors);

    //set company marker
    var companyMarker = createMarker(companyLatLng, companyMarkerImage, companyMarkerSize);

    //set map center
    map.setCenter(companyLatLng, defaultZoomLevel);
    map.addOverlay(companyMarker);
  }
}
</pre>
<p>
  The first thing we need to do is check if the browser is compatible with Google Maps, and for this Google provides the <a href="http://code.google.com/apis/maps/documentation/reference.html#GBrowserIsCompatible">GBrowserIsCompatible()</a> in their API. In essence it returns true if the browser is compatible and allows us to move into the rest of our function. I decided to abstract some of the values to variables at the top of the function so that this could easily be ported to many applications.
</p>
<pre name="code" class="js">
  //settings
  var companyMarkerImage= "./images/jayhawk.gif";
  var companyLatLng     = new GLatLng(38.957101, -95.251469);
  var companyMarkerSize = new GSize(55, 52); //width, height

  toAddress = "1450 Jayhawk Blvd #223 Lawrence, KS 66045";

  var defaultZoomLevel  = 13;
  //end settings
</pre>
<p>
  The <strong>companyMarkerImage</strong> is a string of the location of a small image we will place at our location on the map. This is something I think is a nice touch to have a custom icon to represent your business which will personalize the generic Google Map view. Next, <strong>companyLatLng</strong> holds a <a href="http://code.google.com/apis/maps/documentation/reference.html#GLatLng">GLatLng</a> object corresponding to a latitude, longitude point in the world. Don&#8217;t run out and buy a GPS device to get these numbers we can use <a href="http://maps.google.com">maps.google.com</a> . In the search box type your address and when it finds the location click the <strong>Link</strong> button on the top right of the map. Scroll through the first text box in the modal window and find <strong>&#038;sll=&#8230;</strong>.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/365_googleMaps/images/3.png" border="0" /></div>
<p>
  You can copy and paste those coordinates into the parameters of our GLatLng constructor. This is the point on the map where we will place our custom image. The next variable, <strong>companyMarkerSize</strong>, holds a <a href="http://code.google.com/apis/maps/documentation/reference.html#GSize">GSize</a> object which represents the width and height of your custom marker image. Next we set <strong>toAddress</strong> which is the address of the business. The final variable, <strong>defaultZoomLevel</strong>, just tells the map what you want the default zoom level to be ranging from 1 to 18.
</p>
<pre name="code" class="js">
  //setup elements
  map   = new GMap2(document.getElementById("map_canvas"));
  gdir  = new GDirections(map, document.getElementById("directions"));
</pre>
<p>
  The next line of code creates a <a href="http://code.google.com/apis/maps/documentation/reference.html#GMap2">GMap2</a> object. Google describes this as &#8220;the central class in the API.&#8221; This loads the map data and allows us to manipulate what is shown in the map area. It takes one argument a DOM object pointing to the element containing the map, <strong>#map_canvas</strong>. Next we set <strong>gdir</strong> to hold the <a href="http://code.google.com/apis/maps/documentation/reference.html#GDirections">GDirections</a> object. This is the interface we use to query Google Maps for directions. The constructor takes two arguments a map object and a DOM object where we want to put the turn-by-turn directions. I choose to create an empty div below <strong>#addresses</strong> called <strong>#directions</strong>.
</p>
<pre name="code" class="js">
  //error handler
  GEvent.addListener(gdir, "error", handleErrors);
</pre>
<p>
  When using web services we always run the risk of getting an error returned. We can make this as pain free as possible using the <a href="http://code.google.com/apis/maps/documentation/reference.html#GEvent">GEvent</a> class. In this bit of code we are saying that if we have an error getting the directions to execute a custom callback function, <strong>handleErrors</strong> in our case. We directly call the <a href="http://code.google.com/apis/maps/documentation/reference.html#GEvent.addListener">addListener()</a> function which registers a callback. It takes 3 arguments a source object, a string referring to the type of event we want to execute the callback on, and a handler which points to a function we want executed. The function, <strong>handleErrors</strong>, is something we will look at later.
</p>
<pre name="code" class="js">
  //set company marker
  var companyMarker = createMarker(companyLatLng, companyMarkerImage, companyMarkerSize);

  //set map center
  map.setCenter(companyLatLng, defaultZoomLevel);
  map.addOverlay(companyMarker);
</pre>
<p>
  The last few lines in <strong>initialize()</strong> are used to create our custom marker, I chose a Jayhawk found on <a href="http://ku.edu">KU&#8217;s homepage</a>. <strong>createMarker</strong> is a wrapper function I wrote to abstract the code required to create a custom marker. It takes three arguments: a reference to a <a href="http://code.google.com/apis/maps/documentation/reference.html#GLatLng">GLatLng</a> object where we want to place the image on the, a string respresenting the path to an image, and a reference to a <a href="http://code.google.com/apis/maps/documentation/reference.html#GSize">GSize</a> object that represents the size of the image. Next we use the <a href="http://code.google.com/apis/maps/documentation/reference.html#GMap2.setCenter">setCenter()</a> method of the <a href="http://code.google.com/apis/maps/documentation/reference.html#GMap2">GMap2</a> class which takes two arguments a <a href="http://code.google.com/apis/maps/documentation/reference.html#GLatLng">GLatLng</a> object of the coordinates to center on, and an integer for the zoom level. Notice we are passing in the variables we set in the settings block at the top of the <strong>initialize()</strong> function. The final line of code uses the <a href="http://code.google.com/apis/maps/documentation/reference.html#GMap2.addOverlay">addOverlay()</a> method. This is what actually adds the custom image to the map.
</p>
<p>
  The <strong>initialize()</strong> function does a lot of heavy lifting, but it certainly can show for it. After we write the <strong>createMarker()</strong> function next you will be able to load up the application and see some progress. But first lets recap the <strong>initialize()</strong> function.
</p>
<h3>The createMarker() Function</h3>
<p>
  Next we will create a wrapper function that takes all the pain out of creating a marker with a custom image. The reason I choose to abstract this is because it is an involved process and would clutter up our <strong>initialize()</strong> function even more. Another added benefit is that we can add multiple markers very quickly without repeating a lot of code.
</p>
<pre name="code" class="js">
/*
**
* Wrapper function to create/return a marker object
* with custom image
*/
function createMarker(latlng, imageURL, imageSize)
{

    var marker      = new GIcon(G_DEFAULT_ICON, imageURL);
    marker.iconSize = imageSize;

    return new GMarker(latlng, { icon: marker });

}
</pre>
<p>
  Considerably smaller than our first function, but just as important. First we declare a new variable, <strong>marker</strong>, and store a <a href="http://code.google.com/apis/maps/documentation/reference.html#GIcon">GIcon</a> object. It can take two arguments copy which is a GIcon object that it will copy properties from, and image which is a string representing a path to a custom image. <strong>G_DEFAULT_ICON</strong> is a constant that represents a default marker, and the imageURL comes from the settings block in <strong>initialize()</strong>. We only have to set one more property, <a href="http://code.google.com/apis/maps/documentation/reference.html#GIcon.iconSize">iconSize</a> which is of type <a href="http://code.google.com/apis/maps/documentation/reference.html#GSize">GSize</a>, this represents the size of our custom image and also comes from the settings block. The final line of code returns a <a href="http://code.google.com/apis/maps/documentation/reference.html#GMarker">GMarker</a> object which takes two arguments latlng, and icon. The first, latlng is a reference to the GLatLng object we declared in the settings block. The next argument is for the GIcon object we just created. That is all we need to do for the map portion of our application to work. You can now load up the page and see how easy it is to get a nice map on our website.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/365_googleMaps/images/4.png" border="0" /></div>
<h3>Adding Directions</h3>
<p>
  This is by far my favorite part about this tutorial, allowing users to enter an address and receive back a map with the route highlighted and turn-by-turn directions. Through the use of this API we can condense something that would require thousands of lines of code and an incredible amount of processing resources to just a handful of code.
</p>
<pre name="code" class="js">
/*
**
* Looks up the directions, overlays route on map,
* and prints turn-by-turn to #directions.
*/

function overlayDirections()
{
    fromAddress =
      document.getElementById("street").value
      + " " + document.getElementById("city").value
      + " " + document.getElementById("state").options[document.getElementById("state").selectedIndex].value
      + " " + document.getElementById("zip").value;

    gdir.load("from: " + fromAddress + " to: " + toAddress);
}
</pre>
<p>
  The first line I have actually extended into five lines for clarity. In essence this grabs all the values from the form and puts a space between each part. I thought this was better than asking the user to enter the whole address into a single text box because that can become confusing.
</p>
<p>
  The second line makes use of the <strong>gdir</strong> we set in <strong>initialize()</strong>. We call the <a href="http://code.google.com/apis/maps/documentation/reference.html#GDirections.load">load()</a> method and pass a single string argument, which is essentially what we would pass <a href="http://maps.google.com">maps.google.com</a> via the search box. The <strong>from:</strong> and <strong>to:</strong> keywords help tell Google which address needs to be the starting point and which needs to be the ending point. That is all we need to do for directions, yeah I was shocked too! If you visit your page again you can see this in action.
</p>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/365_googleMaps/images/5.png" border="0" /></div>
<h3>Handling Errors</h3>
<p>
  Next we are going to declare the <strong>handleErrors()</strong> function. I grabbed this from Google Sample code on their API website. I won&#8217;t go into any detail because it fairly straightforward.
</p>
<pre name="code" class="js">
  function handleErrors(){
     if (gdir.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
       alert("No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.\nError code: " + gdir.getStatus().code);
     else if (gdir.getStatus().code == G_GEO_SERVER_ERROR)
       alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + gdir.getStatus().code);
     else if (gdir.getStatus().code == G_GEO_MISSING_QUERY)
       alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + gdir.getStatus().code);
     else if (gdir.getStatus().code == G_GEO_BAD_KEY)
       alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: " + gdir.getStatus().code);
     else if (gdir.getStatus().code == G_GEO_BAD_REQUEST)
       alert("A directions request could not be successfully parsed.\n Error code: " + gdir.getStatus().code);
     else alert("An unknown error occurred.");
  }
</pre>
<p>
  It has a long if&#8230;elseif&#8230;else statement that checks for many error types and alerts the user if any occur. You can modify this if you wish to make the alert less technical.
</p>
<h3>Degradable</h3>
<p>
  As good web developers we should make sure our website works for as many users as possible, including those with JavaScript disabled. In this situation I chose to redirect those with JS disabled to Google Maps with the search performed so they still get directions. This is done using PHP to evaluate the form and redirect to Google Maps. At the top of your HTML page insert this code:
</p>
<pre name="code" class="php">
&lt;?php
  //settings

    $TO    = "1450 Jayhawk Blvd #223 Lawrence, KS 66045"; //company address

  //end settings

  //they seem to have JS disabled, let's redirect them to
  //Google Maps and prefill the query
  if($_POST['submit']) {
    $FROM  = $_POST['street'] . " " . $_POST['city'] . ", " . $_POST['state'] . " " . $_POST['zip'];
    $LOC   = $_POST['language'];

    $url   = "http://maps.google.com/maps?hl=".urlencode($LOC)."&#038;q=from:".urlencode($FROM)."+to:".urlencode($TO)."&#038;ie=UTF8";

    header("Location: " . $url);
  }
?&gt;
...
</pre>
<p>
  First we have a settings block again which only has one variable to set, <strong>$TO</strong>. This is similar to what we did in JavaScript for <strong>toAddress</strong>, but we need the same string in PHP too. Next we have an if statement to check for POSTed data which means our form was submitted. Now we grab the form values and place them in a string with spaces and store that in a variable, <strong>$FROM</strong>. Then we store the language value to <strong>$LOC</strong>, more on this later. The <strong>$url</strong> variable will hold the string representing the query URL to Google. Notice that we url-encode our values so they safely travel on the redirect. The final line of code uses PHP headers to redirect the user to Google.
</p>
<h3>Optional: Add Multi-Language Support</h3>
<p>
  As a business you want to reach out to as many people as possible and part of that process is supporting multiple languages. In Google Maps supporting other languages comes at no extra cost to us.
</p>
<p>
  First open up your HTML page and insert the following code between your form tags.
</p>
<pre name="code" class="html">
...
&lt;select id="language" name="language"&gt;
  &lt;option value="en" selected&gt;English&lt;/option&gt;
  &lt;option value="fr"&gt;French&lt;/option&gt;
  &lt;option value="de"&gt;German&lt;/option&gt;
  &lt;option value="ja"&gt;Japanese&lt;/option&gt;
  &lt;option value="es"&gt;Spanish&lt;/option&gt;
&lt;/select&gt;
...
</pre>
<p>
  Of course if you want to remove any languages just delete the option tag for it, you can also change the default by moving the selected attribute.
</p>
<p>
  Moving to <strong>js/application.js</strong>, we need to make just two changes. Starting in the <strong>overlayDirections()</strong> function after we create the string <strong>fromAddress</strong> add this to grab the selected value from the language select box and save it to our language variable.
</p>
<pre name="code" class="js">
...
var language  = document.getElementById("language").options[document.getElementById("language").selectedIndex].value;
...
</pre>
<p>
  Next, add an argument to the <strong>gdir.load()</strong> function, this takes an options set. In our case we only need to declare <strong>locale</strong> so it knows the proper language and units for the turn-by-turn directions.
</p>
<pre name="code" class="js">
...
gdir.load("from: " + fromAddress + " to: " + toAddress, { "locale": language });
...
</pre>
<p>
  <strong>Note</strong>: We already included this in the PHP redirect and if you want to disable this just statically set <strong>$LOC</strong>.
</p>
<pre name="code" class="php">
...
$LOC = 'en'
...
</pre>
<div class="tutorial_image"><img src="http://nettuts.s3.amazonaws.com/365_googleMaps/images/6.png" border="0" /></div>
<h3>Conclusion</h3>
<p>
  That is all we need for this amazing feature, and I hope you learned a bit about Google Maps along the way. I challenge you as developers to continue to find interesting ways to integrate maps in to your applications. Anytime a model is location aware, you should question if your project has a use for visual representation on a map. Thanks for reading; as always, I am here to help in the comments or on Twitter (<a href="http://twitter.com/noahhendrix">@noahhendrix</a>).
</p>
<ul class="webroundup">
<li>Follow us on <a href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/XyXIfgSfEP_s3hBYDrUw-GybVR0/0/da"><img src="http://feedads.g.doubleclick.net/~a/XyXIfgSfEP_s3hBYDrUw-GybVR0/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/XyXIfgSfEP_s3hBYDrUw-GybVR0/1/da"><img src="http://feedads.g.doubleclick.net/~a/XyXIfgSfEP_s3hBYDrUw-GybVR0/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=_pakOrUGy18:vmjR7vHwKH4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=_pakOrUGy18:vmjR7vHwKH4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=_pakOrUGy18:vmjR7vHwKH4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=_pakOrUGy18:vmjR7vHwKH4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=_pakOrUGy18:vmjR7vHwKH4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=_pakOrUGy18:vmjR7vHwKH4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=_pakOrUGy18:vmjR7vHwKH4:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=_pakOrUGy18:vmjR7vHwKH4:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/_pakOrUGy18" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/tutorials/javascript-ajax/turn-by-turn-directions-with-the-google-maps-api/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/tutorials/javascript-ajax/turn-by-turn-directions-with-the-google-maps-api/</feedburner:origLink></item>
		<item>
		<title>30 Exceptional Web Designs</title>
		<link>http://feedproxy.google.com/~r/nettuts/~3/RnqfJ4QuiSs/</link>
		<comments>http://net.tutsplus.com/articles/web-roundups/30-exceptional-web-designs-for-the-web/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 15:19:50 +0000</pubDate>
		<dc:creator>Sean Geng</dc:creator>
		
		<category><![CDATA[Web Roundups]]></category>

		<category><![CDATA[inspiration]]></category>

		<guid isPermaLink="false">http://net.tutsplus.com/?p=5613</guid>
		<description><![CDATA[<img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/200x200.jpg" alt="30 Exceptional New Designs for the Web" />]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve compiled a list of 30 exceptional web page designs for your inspiration.  Most of these are relatively new; so they&#8217;ll hopefully give you some ideas for your next project!  Enjoy!
</p>
<p><span id="more-5613"></span></p>
<h3>1. <a href="http://alexarts.ru/en/index.html">Alexarts</a></h3>
<p>Alex uses a very simple but modern interface for his site.  Click on any of the sections, and a popup displays.</p>
<div class="tutorial_image"><a href="http://alexarts.ru/en/index.html"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image1.jpg" border="0" /></a></div>
<h3>2. <a href="http://www.pampaneo.es/">Pampaneo</a></h3>
<p>Pampaneo uses excellent graphics and illustrations to tell a story.</p>
<div class="tutorial_image"><a href="http://www.pampaneo.es/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image2.jpg" border="0" /></a></div>
<h3>3. <a href="http://www.juandiegovelasco.com/">Juan Diego Velasco</a></h3>
<p>Juan uses a one page layout and vivid colors for his site.</p>
<div class="tutorial_image"><a href="http://www.juandiegovelasco.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image3.jpg" border="0" /></a></div>
<h3>4. <a href="http://metalabdesign.com/">Metalab</a></h3>
<p>Metalab has a very clean and usable interface, as well as some nice JavaScript effects.</p>
<div class="tutorial_image"><a href="http://metalabdesign.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image4.jpg" border="0" /></a></div>
<h3>5. <a href="http://www.serj.ca/">Serj</a></h3>
<p>Serj features great graphics and a simple and effective layout.  Sometimes, simplicity is key.</p>
<div class="tutorial_image"><a href="http://www.serj.ca/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image5.jpg" border="0" /></a></div>
<h3>6. <a href="http://www.peter-pearson.com/">Peter Pearson</a></h3>
<p>Peter also uses a neat one page layout and some cool image effects.</p>
<div class="tutorial_image"><a href="http://www.peter-pearson.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image6.jpg" border="0" /></a></div>
<h3>7. <a href="http://cactuar.in.the.phailbucket.com/">Cactuar.in.the.Phailbucket</a></h3>
<p>Cole uses excellent vector illustrations and a great choice of colors in his design.</p>
<div class="tutorial_image"><a href="http://cactuar.in.the.phailbucket.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image7.jpg" border="0" /></a></div>
<h3>8. <a href="http://fredmaya.com/">Fred Maya</a></h3>
<p>Fred focuses on simplicity, colors, and usability for this nice design.</p>
<div class="tutorial_image"><a href="http://fredmaya.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image8.jpg" border="0" /></a></div>
<h3>9. <a href="http://www.gavincastleton.com/">Galvin Castleton</a></h3>
<p>This album site uses a one page horizontal layout and excellent photography.</p>
<div class="tutorial_image"><a href="http://www.gavincastleton.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image9.jpg" border="0" /></a></div>
<h3>10. <a href="http://chrisjennings.com/">Chris Jennings</a></h3>
<p>Readability is key.</p>
<div class="tutorial_image"><a href="http://chrisjennings.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image10.jpg" border="0" /></a></div>
<h3>11. <a href="http://en.guerra-creativa.com/">Guerra Creative</a></h3>
<p>Excellent graphics and easy to read content.</p>
<div class="tutorial_image"><a href="http://en.guerra-creativa.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image11.jpg" border="0" /></a></div>
<h3>12. <a href="http://www.84colors.com/index.html">84 Colors</a></h3>
<p>Cristiana&#8217;s thinks outside the box with this different layout.</p>
<div class="tutorial_image"><a href="http://www.84colors.com/index.html"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image12.jpg" border="0" /></a></div>
<h3>13. <a href="http://feedstitch.com/">Feed Stitch</a></h3>
<p>Feed Stitch&#8217;s site is a fun, creative, and super creative!</p>
<div class="tutorial_image"><a href="http://feedstitch.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image13.jpg" border="0" /></a></div>
<h3>14. <a href="http://www.webleeddesign.com/">We Bleed Design</a></h3>
<p>We Bleed Design uses images creatively to animate the transition through sections.</p>
<div class="tutorial_image"><a href="http://www.webleeddesign.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image14.jpg" border="0" /></a></div>
<h3>15. <a href="http://www.mootygraphicdesign.com.au/">Motty</a></h3>
<p>Mooty&#8217;s site uses a great illustration in the header, and the content&#8217;s presentation is excellent. </p>
<div class="tutorial_image"><a href="http://www.mootygraphicdesign.com.au/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image15.jpg" border="0" /></a></div>
<h3>16. <a href="http://www.cerity.se">Cerity</a></h3>
<p>Jonathan&#8217;s portfolio offers a neat interface for viewing his work.</p>
<div class="tutorial_image"><a href="http://www.cerity.se"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image16.jpg" border="0" /></a></div>
<h3>17. <a href="http://cpeople.ru/">Creative People</a></h3>
<p>CreativePeople&#8217;s page has excellent graphics and an interesting layout.</p>
<div class="tutorial_image"><a href="http://cpeople.ru/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image17.jpg" border="0" /></a></div>
<h3>18. <a href="http://brooklynfare.com/index.php">Brooklyn Fare</a></h3>
<p>Brooklyn Fare&#8217;s site is a wonderful example of how a company&#8217;s site should be presented.</p>
<div class="tutorial_image"><a href="http://brooklynfare.com/index.php"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image18.jpg" border="0" /></a></div>
<h3>19. <a href="http://www.tierravirtual.com/">Tierra Virtual</a></h3>
<p>This agency&#8217;s site uses an animated header, and has a modern feel.</p>
<div class="tutorial_image"><a href="http://www.tierravirtual.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image19.jpg" border="0" /></a></div>
<h3>20. <a href="http://www.merixusa.com/">Merixusa</a></h3>
<p>Cute illustrations &#8212; a creative showcase of their work.</p>
<div class="tutorial_image"><a href="http://www.merixusa.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image20.jpg" border="0" /></a></div>
<h3>21. <a href="http://foodincmovie.com/">Food, Inc</a></h3>
<p>Simple and clean site with nice graphics.</p>
<div class="tutorial_image"><a href="http://foodincmovie.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image21.jpg" border="0" /></a></div>
<h3>22. <a href="http://www.tanq.cl/">Inicio</a></h3>
<p>Beautiful choice of colors here.</p>
<div class="tutorial_image"><a href="http://www.tanq.cl/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image22.jpg" border="0" /></a></div>
<h3>23. <a href="http://www.ccsi.be/en/">CCSI</a></h3>
<p>CCSI uses clean graphics and a nice scrolling text effect to draw the reader in.</p>
<div class="tutorial_image"><a href="http://www.ccsi.be/en/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image23.jpg" border="0" /></a></div>
<h3>24. <a href="http://www.loodo.com.br/">Loodo</a></h3>
<p>This website fits a lot of content into a small space &#8212; seemingly with ease! It also makes use of a cute and creative navigation section.</p>
<div class="tutorial_image"><a href="http://www.loodo.com.br/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image24.jpg" border="0" /></a></div>
<h3>25. <a href="http://www.guifx.com/">Guifx</a></h3>
<p>Bells and whistles don&#8217;t always get your point across. Sometimes, simplicity and ease of use is key.</p>
<div class="tutorial_image"><a href="http://www.guifx.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image25.jpg" border="0" /></a></div>
<h3>26. <a href="http://www.vyniknite.sk/">Vyniknite</a></h3>
<p>All websites mustn&#8217;t look identical. Even something as simple as a unique header can make a huge difference.</p>
<div class="tutorial_image"><a href="http://www.vyniknite.sk/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image26.jpg" border="0" /></a></div>
<h3>27. <a href="http://two24studios.com/">two24studios</a></h3>
<p>Great textures, typography, and navigation in this dark website.</p>
<div class="tutorial_image"><a href="http://two24studios.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image27.jpg" border="0" /></a></div>
<h3>28. <a href="http://www.illusiv.nl/">Illusiv</a></h3>
<p>Very creative desktop-like interface.</p>
<div class="tutorial_image"><a href="http://www.illusiv.nl/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image28.jpg" border="0" /></a></div>
<h3>29. <a href="http://www.duirwaigh.com/">Duirwaigh</a></h3>
<p>What a background! Though not appropriate for every site, this one definitely makes an impact.</p>
<div class="tutorial_image"><a href="http://www.duirwaigh.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image29.jpg" border="0" /></a></div>
<h3>30. <a href="http://www.bkwld.com/">BKWLD</a></h3>
<p>Wonderfully effective, with plenty of white space. What more could you ask for?</p>
<div class="tutorial_image"><a href="http://www.bkwld.com/"><img src="http://nettuts.s3.amazonaws.com/364_exceptionalSites/image30.jpg" border="0" /></a></div>
<h3>Final Words</h3>
<p>I hope you found some inspiration here. I know I did!  Be sure to leave a comment to share any additional sites with the rest of us. Good luck on your next project!</p>
<ul class="webroundup">
<li>Follow us on <a href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a href="http://feeds.feedburner.com/nettuts" title="NETTUTS RSS Feed">NETTUTS RSS Feed</a> for more daily web development tuts and articles.</li>
</ul>
<p>
<script type="text/javascript"><!--digg_url = "post permalink (not digg url)"; // -->
</script><br />
<script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>

<p><a href="http://feedads.g.doubleclick.net/~a/8QuRT3yZmoiooGPHj5UyVDL1y3w/0/da"><img src="http://feedads.g.doubleclick.net/~a/8QuRT3yZmoiooGPHj5UyVDL1y3w/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/8QuRT3yZmoiooGPHj5UyVDL1y3w/1/da"><img src="http://feedads.g.doubleclick.net/~a/8QuRT3yZmoiooGPHj5UyVDL1y3w/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=RnqfJ4QuiSs:jTVDE0gP_9Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=RnqfJ4QuiSs:jTVDE0gP_9Q:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=RnqfJ4QuiSs:jTVDE0gP_9Q:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=RnqfJ4QuiSs:jTVDE0gP_9Q:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=RnqfJ4QuiSs:jTVDE0gP_9Q:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=RnqfJ4QuiSs:jTVDE0gP_9Q:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=RnqfJ4QuiSs:jTVDE0gP_9Q:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=RnqfJ4QuiSs:jTVDE0gP_9Q:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/RnqfJ4QuiSs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://net.tutsplus.com/articles/web-roundups/30-exceptional-web-designs-for-the-web/feed/</wfw:commentRss>
		<feedburner:origLink>http://net.tutsplus.com/articles/web-roundups/30-exceptional-web-designs-for-the-web/</feedburner:origLink></item>
	</channel>
</rss>
