Web International Awards

payday loan

8

JUN 2010 8

Building a live news blogging system in php. Spiced with HTML5, CSS3 and jQuery [end]

Tutorial app preview

Finally, the last part of the tutorial you have all been waiting for. Until now I've covered everything that deals with databases and the CRUD functionalities the system has. However, I haven't tackled the primary view of the app, the homepage, which automatically updates news as they are added in the database without requiring anything from the end user. To bad I didn't finish the tutorial earlier; maybe some great online newspapers would have used it during yesterday's keynote address at WWDC.

HTML5 modifications, integration with php

In case you read all the previous parts of the tutorial, you know I used HTML5 to structure the layout of the app. While implementing some of the functionalities, small upgrades were required. I am going to start with the head of the document. There are two stylesheets added. One is for general styles, while the second one is used to style the datepicker used in the app and is the style that comes with jQuery's datepicker plugin. Having that said, you can see there's also the .js script for it and for jQuery as well. date.js is Jörn Zaefferer's and Brandon Aaron's date prototype extensions I've used in the app. The sprinkle.js file is where all the gizmoz performed by the app are stored.

1
2
3
4
5
6
7
8
9
10
<head>
	<title>Live News System</title>
	<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" title="no title" charset="utf-8">
	<link rel="stylesheet" href="css/datepicker.css" type="text/css" media="screen" title="no title" charset="utf-8">
 
	<script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
	<script src="js/date.js" type="text/javascript" charset="utf-8"></script>
	<script src="js/datepicker.js" type="text/javascript" charset="utf-8"></script>
	<script src="js/sprinkle.js" type="text/javascript" charset="utf-8"></script>	
</head>

Moving on to the body of the site the first items contained in the body are hidden to public view. It's a small php script that includes the functions file and calls for the initiateLastID() function. This function is newly added, and its code is provided just below.

1
2
3
4
5
6
7
8
9
<body>
 
	<? include("includes/functions.php");
	   initiateLastID(); 
	?>
 
	<header class="top-rounded">
		Live News System <!-- The title of our app -->         
	</header>
1
2
3
4
5
6
7
8
9
10
11
12
function initiateLastID()
{
	if(!session_is_registered('lastID'))
	{ 
		// no previous call
		session_register('lastID');
		$query = "SELECT id FROM News WHERE id>0 ORDER BY id DESC LIMIT 1";
		$data = mysql_query($query) or die(mysql_error());
		$_SESSION['lastID'] = $data['id'];
		$lastID = $data['id'];
	}
}

What this function does is it creates a php session that contains the ID of the last news item added to the database. This session will be used to track new news added in the database while the user is on the homepage. This is a key variable in achieving a functionality similar to Twitter's new X items in search page.

Next, just after the details tag in the header of the page, the one which stores and displays information regarding selected filters, we add some more php code. The code is shown below and its purpose is to catch error and notification messages directly from the URL and display them nicely inside the webapp's UI.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?
$msg = $error = "";
$msg=$_REQUEST['msg'];
$error=$_REQUEST['error'];
if($msg!="")
{
	?>
	<article class="no-hover message display">
		<h1><?=$msg?></h1>
	</article>
	<?
}
if($error!="")
{
	?>
	<article class="no-hover error display">                      
		<h1><?=$error?></h1>
	</article>
	<?
}
list_news();
?>

list_news() is a bit complex, and will be presented in just a few minutes.

In the right sidebar we have the start date and end date input fields. We need to store the information within these fields as users could accidentally click the refresh button of the web browser and loose data in those input fields. We protect the information in the fields by storing it using php sessions. The modified code for the two inputs is the following one:

1
2
3
4
5
6
<fieldset>
	<label for="start_date">Start date: </label>
	<input type="text" name="start_date" value="<?=$_SESSION['start']?>" id="start_date" class="date-pick">
	<label for="end_date">End date: </label>
	<input type="text" name="end_date" value="<?=$_SESSION['end']?>" id="end_date" class="date-pick">
</fieldset>

Just below the two date inputs the categories of the webapp are listed. This is achieved by using a php function: list_categories() which was presented in the third part of the tutorial. However, during that part the function returned option values for select tags. The updated function is shown below.

1
2
3
4
<ul><!-- This UL will hold our categories -->
	<li class="title">Browse by category</li>                     
	<? list_categories("") ?>
</ul>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function list_categories($mode)
{
	if(session_is_registered('categories')) $categories = $_SESSION['categories'];
 
	$rows = mysql_query("SELECT name FROM Categories WHERE id>0 ORDER BY name ASC") or die(mysql_error());
	if($mode=="")
	{
		if(mysql_num_rows($rows))
		{
			while($row = mysql_fetch_row($rows))
			{
				if(session_is_registered('categories')) 
					{
						if(sizeof($categories)>0)
						{
							if(array_key_exists($row[0],$categories)) echo "<li><a class=\"selected-aside\">".$row[0]."</a></li>";
								else echo "<li><a>".$row[0]."</a></li>";
						}
						else echo "<li><a>".$row[0]."</a></li>";
					}
				else echo "<li><a>".$row[0]."</a></li>";
			}
		}
		else echo "<li>no categories</li>";
	}
	else if($mode=="select-options")
	{
	// code in part three of the tutorial
	}
}

What the function does is find out which categories are already selected by the user, then display them as list items. If some of them are selected, the selected-aside class is appended to the li tag. Moreover, the $mode param used in this function determines if the function should return li tags or option tags.

The footer has also been updated and now tracks user login and displays information accordingly.

1
2
3
<footer>
	<? if(!session_is_registered('loggedin')) { ?><a rel="login" name="modal">Admin login</a> <? } else { ?>You are logged in. You can <A  href="#addnews" rel="addnews" name="modal">add news</a> or <a href="logout.php" target="_self">logout</a><? } ?>
</footer>

With this we've finished the HTML structure and content of the index page. Before moving on to the jQuery code which is used to add all the awesome functionalities let me remind you what the structure of an article is (referring to HTML article tag). Just below are presented two different structures, one used for showcasing news to end users while the second is used to display the news to admins that are logged in.

1
2
3
4
5
<article>	
	<h1>news title</h1>
	<details>Posted by <span>user</span> in <span class="cat">category</span> on <span>date</span> at <span>time</span>.</details>
	<p>content of news</p>
</article>
1
2
3
4
5
6
<article>
	<span class="controls"><a href="deletenews.php?id=ID" target="_self" class="delete"></a><a href="" name="modal" rel="editform" title="ID" target="_self" class="edit"></a></span>	
	<h1>news title</h1>
	<details>Posted by <span>user</span> in <span class="cat">category</span> on <span>date</span> at <span>time</span>.</details>
	<p>content of news</p>
</article>

As you can see the code used for admins contains an extra span with links to the edit and delete buttons for the news item.

list_news()

Based on the average complexity of the functions presented up to this point, this function that spans across 100 lines of code is huge. Check out the code, try to understand it. Explanations will follow just after it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
function list_news()
{
	$categories_query = "";
	if(session_is_registered('categories'))
		{ // we have some registered categories, so our query will not select all news
			if(sizeof($_SESSION['categories'])>0)
			{
				$categorieskeys = array_keys($_SESSION['categories']);
				$count = 0;
				if(sizeof($categorieskeys)>0)
				{
					$categories_query = "AND (";
					while($categorieskeys[$count]!=null)
					{
						if($count>0) $categories_query = $categories_query." OR category = '".$categorieskeys[$count]."' ";
						else $categories_query = $categories_query." category = '".$categorieskeys[$count]."' ";
						$count++;
					}
					$categories_query = $categories_query . " ) ";				
				}
			}
		}
 
	$start = $_SESSION['start'];
	$end = $_SESSION['end'];	
 
	if($categories_query!='')
	{
		if((session_is_registered('start'))&&(session_is_registered('end'))&&(strlen($start)!=0)&&(strlen($end)!=0))
		{
			$query = "SELECT * FROM News WHERE id>0 ".$categories_query." AND  publishing_date >= '$start' AND publishing_date <='$end' ORDER BY publishing_date DESC, publishing_time DESC";
		}
		elseif (session_is_registered('start')&&(strlen($start)!=0))
		{
			$query = "SELECT * FROM News WHERE id>0 ".$categories_query." AND publishing_date >= '$start' ORDER BY publishing_date DESC, publishing_time DESC";
		}
		elseif (session_is_registered('end')&&(strlen($end)!=0))
		{
			$query = "SELECT * FROM News WHERE id>0 ".$categories_query." AND publishing_date <= '$end' ORDER BY publishing_date DESC, publishing_time DESC";
		}
		else $query = "SELECT * FROM News WHERE id>0 ".$categories_query." ORDER BY publishing_date DESC, publishing_time DESC";
	} 
	else 
	{
		if((session_is_registered('start'))&&(session_is_registered('end'))&&(strlen($start)!=0)&&(strlen($end)!=0))
		{
			$query = "SELECT * FROM News WHERE id>0 AND  publishing_date >= '$start' AND publishing_date <= '$end' ORDER BY publishing_date DESC, publishing_time DESC";
		}
		elseif (session_is_registered('start')&&(strlen($start)!=0))
		{
			$query = "SELECT * FROM News WHERE id>0 AND publishing_date >= '$start' ORDER BY publishing_date DESC, publishing_time DESC";
		}
		elseif (session_is_registered('end')&&(strlen($end)!=0))
		{
			$query = "SELECT * FROM News WHERE id>0 AND publishing_date <= '$end' ORDER BY publishing_date DESC, publishing_time DESC";
		}
		else $query = $query = "SELECT * FROM News WHERE id>0 ORDER BY publishing_date DESC, publishing_time DESC";
	}
 
	$newlastID = 0;
 
	$rows = mysql_query($query) or die(mysql_error());
	// row contains ID title body owner publishing_date publishing_time category
	if(mysql_num_rows($rows))
	{
		while($row = mysql_fetch_row($rows))
		{
			if($newlastID==0) 
			{
				$newlastID = $row[0];
				if(session_is_registered('lastID'))
				{ 
					$_SESSION['lastID'] = $newlastID;
					$lastID = $newlastID;
				}
				else
				{ 
					// no previous call
					session_register('lastID');
					$_SESSION['lastID'] = $lastID;
				}				
			}
			if(session_is_registered('loggedin')) $admincontrols = "<span class=\"controls\"><a href=\"deletenews.php?id=".$row[0]."\" target=\"_self\" class=\"delete\"></a><a href=\"\" name=\"modal\" rel=\"editform\" title=\"".$row[0]."\" target=\"_self\" class=\"edit\"></a></span>";
			echo "
				<article>
					".$admincontrols."
					<h1>".$row[1]."</h1>
					<details>Posted by <span>".$row[3]."</span> in <span class=\"cat\">".$row[6]."</span> on <span>".$row[4]."</span> at <span>".$row[5]."</span>.</details>
					<p>".$row[2]."</p>
				</article>
			";
		}
	}
	else echo "<article class=\"no-hover\"><h1>No news into the system</h1></article>";
}

The first section of the function starting on the third line and going up to line 22 checks if there are any categories selected. If at least one is selected the code builds a SQL statement which will be used in a SELECT / WHERE clause.

The code on lines 24 and 25 is used to check whether the start and end dates used for news filtering are enabled. If they are enabled they must to be used in the SELECT statement against the database.

First batch of SELECT statements, starting on line 27 up to 42. This batch is used if the users have selected any categories to filter the results. There are multiple statements because each one of them is used based on start and end date filters contents. The second batch, line 45 to 57, does the same thing as the above batch, but doesn't limit the results based on categories because in this case none of them is selected.

The code between lines 60 to 94 lists the results of the previous SQL queries. $newlastID variable is used to update the $lastID session described above. This is necessary because the ID of the last news added to the system changes as soon as applied filters change. The last news in one category doesn't have the same ID as the last news inside another category, or throughout the entire system. These checks and session updates are done between lines 68 and 82 and are done once per each query.

Finally, the code from line 83 to 90 is used to create the structure and content of each news item and display it.

Further more, there's another similar function as complex as this one. Its name is list_new_news() and the difference between this one and the one presented above is that it uses the lastID session in its SELECT statements, returning items which have an ID bigger than what lastID stores. This function is used to add to the DOM news items that were added to the system after the user has loaded the page.

Basically, this function is used to achieve the functionality of the Twitter new items feature available in Twitter's search page. However, simply coding it won't do any good. This function has to be combined with some ajax requests, which are coded in the sprinkle.js jQuery file.

sprinkle.js

Thank God I've shown parts of this file in the previous five parts of the tutorial. Otherwise, the task for today would have been explaining 400 or more lines of code. Fortunately, some of them are already known so I am going to stick to showing the newly added lines only.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function updateNews(){
	$.get('includes/check_new_items.php',function(newdata){
		if(newdata.length==3) 
		{
		$('#newdata').insertAfter('section > details');	
		// find out each new article, compute height, and set new heights for section and aside
		var sectionHeight = 75; // padding, margin, included elements
		$('section article').each(function(){
			sectionHeight = sectionHeight + $(this).height() + 10 + 25; // 10 comes from padding t b, 25 from margin top
		});
		asideHeight = 0;
		asideHeight = asideHeight + $('aside div').height();
		$('aside li').each(function(){
			asideHeight = asideHeight + $(this).height();
			if($(this).attr('class')=='title') asideHeight = asideHeight + 15;
		});
		if(asideHeight < sectionHeight) 
		{
		//	alert (sectionHeight);
			$('aside, section').animate({ height: sectionHeight },{queue:false}); // update height	
		}
		else
		{
		//	alert (asideHeight);
			$('aside, section').animate({ height: asideHeight },{queue:false}); // update height	
		}
		// done with column heights
		$('section article').fadeIn('slow');
		}
	});
}

The above function checks for new news added into the database. If new items are available, a message stating so is appended to the DOM. If the message box is clicked new news items are appended to the DOM and then faded in so that users can see them. This functions's corresponding php file is similar to the list_news() function. What is changed is the last part of the function which displays the news items, part that has been replaced with the code shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$newLastID = 0;
$nothere = 0;
$rows = mysql_query($query) or die(mysql_error());
// row contains ID title body owner publishing_date publishing_time category
if(mysql_num_rows($rows))
{
	while($row = mysql_fetch_row($rows))
	{
		if($newLastID==0)
		{
			$newLastID = $row[0];
		}
		if(($oldLastID<$newLastID)&&($nothere==0))
		{
			echo "new";
			$nothere = 1;
		}
	}
}

The following code is used to handle clicks performed on the categories listed in the sidebar. What the code does is it checks whether the clicked category is selected. If it is, the category is removed from the php categories session and its visual style changed. If the category is not selected it is appended to the php categories session and its visual appearance changed. The php file that's used to update the session is also shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// change style for aside category selector and filters above content + ajax requests for updating selected categories
$("aside ul li a").click(function (){
	var classAttr = $(this).attr('class');
	if (classAttr != 'selected-aside')
	{
		// update style class for category just clicked
		$(this).attr('class','selected-aside');
		var category = $(this).text();
		$(this).append('<span>X</span>');
		 // check filter legend status and update it if required
		var classAttr = $('.categories').attr('class');
		if(classAttr == 'categories not-selected') $('.categories').attr('class','categories selected');
		// now we need to make an ajax call to add our category to our selected categories session
		var jdata = "function=add&category="+category; 
		$.ajax({
			type: "POST",
			url: "includes/categories_sessions.php",
 				data: jdata 
		});
	}
	else
	{
		// update style class for category just clicked
		$(this).attr('class','');
		var span = $(this).children();
		$(span).remove();
		var category = $(this).text();
		// now we need to make an ajax call to remove our category to our selected categories session
		var jdata = "function=remove&category="+category; 
		$.ajax({
			type: "POST",
			url: "includes/categories_sessions.php",
 				data: jdata 
		});
		// check if there is any category selected
		// if not, update filter legend class
		var anyCatSelected = $('.selected-aside').size();
		if(anyCatSelected==0) 
		{	
			$('.categories').attr('class','categories not-selected');
		}
	}// from else
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?
	session_start(); 
	$err = 0;
	if(isset($_REQUEST['function'])) $function = $_REQUEST['function'];
	else $err = 1;
	if(isset($_REQUEST['category'])) $category = $_REQUEST['category'];
	else $err = 1;
 
	if(!$err)
	{ 
		if($function == 'add')
		{ 
			if(session_is_registered('categories'))
			{ 
				$categories = $_SESSION['categories'];
				$categories[$category] = 1;
				$_SESSION['categories'] = $categories;
			}
			else
			{ 
				// no previous call
				session_register('categories');
				$categories = array();
				$categories[$category] = 1;
				$_SESSION['categories'] = $categories;
			}
 
		}
		elseif($function  == 'remove')
		{
			$categories = $_SESSION['categories'];
			unset($categories[$category]);
			$_SESSION['categories'] = $categories;
		}
	}
 
?>

However, we're not done yet with the functionality. If someone changes the categories which are selected the news must be updated and the following code does that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ajax requests to reload content and resize section + aside
$('section article').fadeOut('slow', function(){ 
		// completion of fading current content out
		//$('section').animate({ height: sectionHeight });  // reset height of section to original value
		if($('section article').length>0) $('section article').remove();
		var oldcontent = $('section').html();
		$.get('includes/load_news.php', function(newdata){
			$('section').html(oldcontent+newdata);
			// find out each new article, compute height, and set new heights for section and aside
			var sectionHeight = 50; // padding, margin, included elements
			$('section article').each(function(){
				sectionHeight = sectionHeight + $(this).height() + 10 + 25; // 10 comes from padding t b, 25 from margin top
			});
			asideHeight = 0;
			asideHeight = asideHeight + $('aside div').height();
			$('aside li').each(function(){
				asideHeight = asideHeight + $(this).height();
				if($(this).attr('class')=='title') asideHeight = asideHeight + 15;
			});
			if(asideHeight < sectionHeight) 
			{
			//	alert (sectionHeight);
				$('aside, section').animate({ height: sectionHeight },{queue:false}); // update height	
			}
			else
			{
			//	alert (asideHeight);
				$('aside, section').animate({ height: asideHeight },{queue:false}); // update height	
			}
			// done with column heights
			$('section article').fadeIn('slow');
			overlay();
		});
	});
});

Based on the request processed by the load_news.php file we'll probably have to change the content that's visible on the homepage. Therefore, current content is faded out, new content inserted and main content area and sidebar heights updated. Only after these processes are completed the new content is faded in and displayed in the page. The load_news.php file simply calls the load_news() function.

Same content reloading has to take place if users change the date range they want via the two datepickers located in the top of the right sidebar. The process is the same as the one described above in the case of categories being changed with a simple addition to the code. The new addition is the request processed by the datepicker.php file which does some session updating and nothing more. The differences are shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$('#start_date').change(function(){
	// the start date of date picker has been changed
	// ajax call to handle it
	var startdate = $(this).val();
	if(startdate!=null)
	{
		var classAttr = $('.daterange').attr('class');
		if(classAttr == 'daterange not-selected') $('.daterange').attr('class','daterange selected');	
 
			var jdata = "function=start&date="+startdate; 
			$.ajax({
				type: "POST",
				url: "includes/datepicker.php",
				data: jdata 
			});
 
			// load_news.php request as presented above in the tutorial
	}
 
});
 
$('#end_date').change(function(){
	// the start date of date picker has been changed
	// ajax call to handle it
	var enddate = $(this).val();
	if(enddate!=null)
	{
		var classAttr = $('.daterange').attr('class');
		if(classAttr == 'daterange not-selected') $('.daterange').attr('class','daterange selected');	
 
			var jdata = "function=end&date="+enddate; 
			$.ajax({
				type: "POST",
				url: "includes/datepicker.php",
				data: jdata 
			});
 
			// load_news.php request as presented above in the tutorial
	}	
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?
	session_start(); 
	$err = 0;
	if(isset($_REQUEST['function'])) $function = $_REQUEST['function'];
	else $err = 1;
	if(isset($_REQUEST['date'])) $date = $_REQUEST['date'];
	else $err = 1;
 
	if(!$err)
	{ 
		if($function == 'start')
		{ 
			if(session_is_registered('start'))
			{ 
				$start = $_SESSION['start'];
				$start = $date;
				$_SESSION['start'] = $start;
			}
			else
			{ 
				// no previous call
				session_register('start');
				$start = $_SESSION['start'];
				$start = $date;
				$_SESSION['start'] = $start;
			}
		}
		elseif($function  == 'end')
		{
			if(session_is_registered('end'))
			{ 
				$_SESSION['end'] = $date;
			}
			else
			{ 
				// no previous call
				session_register('end');
				$_SESSION['end'] = $date;
			}
		}
		elseif($function == 'clear')
		{
			$start = $_SESSION['start'];
			$start = "";
			$_SESSION['start'] = $start;
 
			$end = $_SESSION['end'];
			$end = "";
			$_SESSION['end'] = $end;
		}
	}	
?>

How do we actually handle new news items. During the first part of the series a hidden div was added to the page structure, which was supposed to be used on a later time. That time has come; let me remind you that small piece of HTML:

1
2
3
<article class="no-hover hidden" id="newdata">
	<h1>New articles in the system. Click here to view them</h1>  
</article>

The above div is hidden but it fades in on top of all the articles if ajax requests show that new items are available in the database and they correspond with user's filters. Checking is the task of the updateNews() function which uses the check_new_items.php file. If new items are available the #newdata div is added on top of the articles displayed in the page, just as described above when the updateNews() function was shown. Here's the code that handles the clicks performed on this div and that fades out current content and displays new news items:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$('#newdata').click(function(){
 
	$('#newdata').insertAfter('footer');	
	$('#newdata').removeAttr('style');
 
	// ajax requests to reload content and resize section + aside
		$('section article').fadeOut('slow', function(){ 
				// completion of fading current content out
				//$('section').animate({ height: sectionHeight });  // reset height of section to original value
				if($('section article').length>0) $('section article').remove();
				var oldcontent = $('section').html();
 
				$.get('includes/load_new_news.php', function(newdata){
					$('section').html(oldcontent+newdata);
 
					// find out each new article, compute height, and set new heights for section and aside
					var sectionHeight = 75; // padding, margin, included elements
					$('section article').each(function(){
						sectionHeight = sectionHeight + $(this).height() + 10 + 25; // 10 comes from padding t b, 25 from margin top
					});
					asideHeight = 0;
					asideHeight = asideHeight + $('aside div').height();
					$('aside li').each(function(){
						asideHeight = asideHeight + $(this).height();
						if($(this).attr('class')=='title') asideHeight = asideHeight + 15;
					});
 
					if(asideHeight < sectionHeight) 
					{
					//	alert (sectionHeight);
						$('aside, section').animate({ height: sectionHeight },{queue:false}); // update height	
					}
					else
					{
					//	alert (asideHeight);
						$('aside, section').animate({ height: asideHeight },{queue:false}); // update height	
					}
					// done with column heights
					$('section article').fadeIn('slow');
					overlay();
				});
			});
});

You'd think that this is all the code we need. Unfortunately, it isn't. Just placing the updateNews() function won't make wonders. We need to call this function on a set interval, 5 or 10 seconds for example. This way the users do not have to reload the page to check for new news as the app periodically checks that for them and displays a notification message if new items are added. The users only have to sit back and enjoy the feed. The code that creates the 10 second loop call of the function is shown below:

1
setInterval( "updateNews()", 10000 );

Conclusion

The webapp could be used to live blog different important events, such as WWDC, Oscars and so on. Moreover, due to the categories filters one could live blog different events simultaneously on the same app.

Source code and demo

As you know from the demo part of the tutorial a demo of the application is available over here. I am working on packing the source codes and they should be available to download, use and extend soon!

If you liked this tutorial series, stay updated to new content via our RSS feed or by email, because a new series will start soon. This new series will be around coding the same webapp using JSP on Tomcat.

Published on Tuesday, June 8th, 2010 at 3:51 pm in tutorials.

About Bogdan Pop

Bogdan Pop is a young Romanian entrepreneur who runs WebRaptor. He is a web developer with awesome design skills, who enjoys writing about everyday's work and usability. He relaxes by taking photos every once in a while and by mixing french electronic music. Connect with him via Twitter.
 
  1. Martin says: February 18th, 2011 at 8:54 pm

    Hello. I like your system but I have a problem with the admin panel. I tried to create an admin in db but not accept it? I’m not very good with mysql. Maybe the mistake is in me:) thanks in advance for the answer ..

  2. Bogdan Pop says: February 18th, 2011 at 9:48 pm

    Hi Martin, do you have phpmyadmin or did you try to run a SQL command by direct input?

    If you could paste in your command it would help a lot in fixing your problem.

  3. Michael says: April 8th, 2011 at 2:38 pm

    Hi Bogdan,

    I have only just discovered your tutorial and I am working my way through it!

    Are there features for archiving news when it gets past a certain age, so lets say if the news has been on display for 90 days, move it to an archive?

    If not how can I implement that within this system?

    Kind Regards,


    Michael

  4. Bogdan Pop says: April 8th, 2011 at 5:25 pm

    Hello Michael,

    Unfortunately there isn’t such a feature. You can implement it by adding a column to the news items in the database (perhaps an enum field with values 0/1 – 1 for archived). Then you would need to setup a cron job to check all old items and archive them automatically and lastly you would need to modify current php scripts to differentiate in the mysql selects between archived and unarchived items.

    We can do it for you if you want, but we’re on a tight schedule already (request quote form).

  5. Michael says: April 16th, 2011 at 9:15 pm

    I was trying to add an instance of the date picker into the add_event section … but I can’t get the date picker to work there … am I missing something simple?

  6. Bogdan Pop says: April 18th, 2011 at 10:24 am

    Hmm, is the datepicker js file included before or after that ?

  7. Harry Orford says: May 25th, 2011 at 1:09 am

    I am trying to run the page but it gives me this error

    Warning: mysql_connect() [function.mysql-connect]: Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2) in /hermes/bosweb/web268/b2686/ipg.hutographycom/includes/functions.php on line 12
    Cannot connect to serverCan’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2)

  8. Bogdan Pop says: May 25th, 2011 at 8:01 am

    Hi Harry,

    please make sure you have your correct settings in the includes/config.php file, otherwise connection won’t work.

    Also, your error is a socket connection error, so I think the issue is not with usernames and password but with your php/mysql configuration. If you’re trying to use the script on a shared hosting, perhaps you should contact your host regarding this issue.

    If you’ve tried to do it on your local computer, then upload your php.ini and my.cnf files and post a link to them here.





Save time next time! You won't have to fill out all these fields again. Register in just a few clicks and then login.


If you do not have a username, you can register in just a few clicks.