**Skip to bottom if you just want the source code and instructions**!
As the festive season approaches, everyone in Britain looks forward to an advent calendar. Actually correction. Everyone looks forward to eating the chocolate from their advent calendar.
At work, I got asked to make an interactive online advent calendar to highlight some of the wonderful historic items in our Library Archive. I had a quick browse of the web to see if anyone else had done something similar, but the closest was some horrific html page from about 1995. Suffice to say, starting from scratch was the only option.
I first thought about what exactly people enjoyed about advent calendars and how that could be recreated digitally:
- Chocolate
- Anticipation
- Self control: only open one window a day
- Viewing the image inside the calendar
- Chocolate
With digital chocolate entirely unsatisfying, it was down the the other things. I needed a advent calendar that would have this functionality:
- Allow people only to open windows for that particular date, or any date before it in December.
- Remember which windows the user had already opened, even after repeated visits each day.
- Present the ‘goodie’ inside the window in an attractive style
- Record that a user has visited a window before.
With these in mind, I set about thinking about the easiest way to achieve these:
- Allow people only to open windows for that particular date, or any date before it in December.PHP Scripting
- Remember which windows the user had already opened, even after repeated visits each day.Cookies
- Present the ‘goodie’ inside the window in an attractive style. Thickbox
- Record that a user has visited a window before.Ajax
Combining JQuery thickbox, with some PHP scripting and cookies should make this crazy crazy dream (!) a reality.
First the layout. I decided on using a simple table to hold all the ‘windows’ in the advent calendar. I could have used DIVS and CSS(remember kids: Tables are a big no no for anything but tabular data, especially layout), however, it was pretty much tabular data I was using so decided to stick with tables.
I created simple content DIV with the background image as an attractive winter scene as the ‘front’ of the advent calendar:
#content
{
background:
url(bg.jpg
) top left no-repeat;
width: 1024px ;
margin-left:
auto ;
margin-right:
auto ;
height:680px;
}
And then placed a table with 8 columns and 3 rows(to make the 24 windows) into this DIV. I styled the cells of the table with a background colour that was semi-transparent(solid block when mouse over), and randomly placed numbers into the cells.
td
{
/* Fallback for web browsers that doesn’t support RGBa */
background:
url(tp.png
);
height:180px;
width:125px;
font-size:55px;
color:#000000;
text-align:
center;
padding:0px;
margin:5px;
filter: expression
((runtimeStyle
.backgroundImage !=
‘none’) ? runtimeStyle
.filter =
‘progid:DXImageTransform.Microsoft.AlphaImageLoader(src=’+currentStyle.backgroundImage.split
(‘\”‘)[1]+
‘, sizingMethod=scale)’ : runtimeStyle.filter,runtimeStyle
.backgroundImage =
‘none’);
}
td:hover{
background-color:#000000;
height:180px;
width:125px;
font-size:55px;
color:#ffffff;
text-align:center;
}
I also then downloaded and installed thickbox for the images to appear in:
<script type=“text/javascript” src=“jquery.js”></script>
<script type=“text/javascript” src=“thickbox.js”></script>
Now I had the basic layout, I had to think about the best way to prevent people clicking on the image before the time was right, but also I had to ensure that any windows that had been opened before would stay open on any subsequent visists. To do this, I decided to just create one big PHP function to do it all. Below I’ll go into detail about this function, but to call it, I put placed the call in the table cell.
<td id=“1″><? check(1,“Theatre programme for a touring production of Billy Liar directed by Lindsay Anderson (1960).<br />
http://www.is.stir.ac.uk/libraries/collections/anderson/LA307.php “);?></td>
The above code calls the function ‘check’ and passes in the number of the window and a brief description of the image that will appear(this is needed for thickbox creation).
The function
The first step was to create a cookie and set it to expire a long time in the future, in this case, 30 days. I used PHP cookies to check for a cookie called ‘seen’ and create one if it doesn’t exist:
session_start();
if (isset($_COOKIE[‘seen’])){
$session=$_COOKIE[‘seen’];
//echo "cookie is".$session;
}
else{
$expire=60*60*24*30;
setcookie(“seen”, “”, time()+$expire);
//echo "session is nowhere";
}
The main guts of the main function had two major operations:
- check for a cookie, and assign the contents of that cookie to a variable that contains all the numbers of the days that have been visited. This would be the mechanism for ensuring the windows stay open after multiple re-visits to the page. This also allowed the page to display the correct window contents: either an open window or a closed one.
- check the current date and ensure that the window is allowed to be open (ensure the user doesn’t eat all the electronic chocolate at once!).
To check which windows the user had opened before, I first got the cookie and assigned it to a variable called $session;
function check
($num,
$blurb){
if (isset($_COOKIE[‘seen’])){
$session=
$_COOKIE[‘seen’];
//echo "sesis".$session;
}
else{
$session=
$_COOKIE[‘seen’]=
“”;
}
I then got the current day of the month as a number, and the month number(i.e 15th Dec would be 15 and 12):
After this I needed to see what days the user had already seen before. The way I had been mainting the cookie was to have the windows(i.e days) that the user had already opened, seperated by a comma. So if a user had opened days 1-5, the cookie would contain: “1,2,3,4,5″. To seperate the contents of this cookie, I simply use the PHP command ‘explode’ with a comma to split up that string of numbers and place it into an array:
This now gave me my visited windows in an array called $array. All I had to do now was check that the number on the advent calendar was allowed to be clicked on(i.e the day has already passed), and that the user had clicked on it before or not.
if ($month ==
12){
if ($num<=$day){
if (in_array($num, $array)) {
$insert=“<img src=’images/t$num.jpg’ alt=’thumbnail for $num’ style=’width:120px;height:180px;margin:0px;padding:0px;’/>”;
}
else{
$insert=$num;
}
echo ‘<a href="images/’.$num.‘.jpg" title="’.$blurb.‘" class="thickbox" onclick="sndReq(\’‘.$num.‘\’)">’.$insert.‘</a>’;
}
else{
echo (“$num”);
}
}//month !=12
else{
echo (“$num”);
}
Let’s break that down a bit:
The first thing I’m doing here is checking that the month is December to make sure no one can access any of the windows before then:
Next, I’m checking to make sure that the window number(which is passed into the function, along with a blurb about the image that will be displayed) is less than or equal to the current day. This is the check to make sure that the user is allowed to click on the number.
After this, I need to do a check to see if the user has actually clicked on the window before, and if they have, they need to be presented with a thumbnail of the larger image they see in the thickbox when they click on the window. To do this, I’m simply checking to see if the passed in number ($num) exists in the array that was created from the cookie. It assigns a string to the variable $insert that either just has the number as a clickable link, or displays a thumbnail of the image if it has been clicked on before(i.e it was in the cookie). The thumbnail image is called t+window number.jpg. After it does this check it will print on the page either the thumbnail image or just the clickable number. Both link to the same place, it’s just whether it displays the number of the window or the thumbnail image.
if (in_array($num,
$array)) {
$insert=
“<img src=’images/t$num.jpg’ alt=’thumbnail for $num’ style=’width:120px;height:180px;margin:0px;padding:0px;’/>”;
}
else{
$insert=
$num;
}
echo ‘<a href="images/’.$num.‘.jpg" title="’.$blurb.‘" class="thickbox" onclick="sndReq(\’‘.$num.‘\’)">’.$insert.‘</a>’;
Each link has a class as ‘thickbox’ that will open the image in a new thickbox on that page along with the description which is the ‘title=’ in the link.
You’ll noticed an ‘onclick’ action that takes place when the user clicks on the window link. This is to use Ajax to silently record the window number that the user had clicked on to the cookie of visited windows. Let’s take a look at this:
The AJAX bit
echo ‘<a href="images/’.
$num.
‘.jpg" title="’.
$blurb.
‘" onclick="sndReq(\’‘.
$num.
‘\’)">’.
$insert.
‘</a>’;
The onclick=”sndReq(\”.$num.’\')” calls a javscript function that passes in the number of the window the user just clicked on. This goes to some Ajax that then runs a PHP script to add that clicked on number to the cookie:
<script type=
“text/javascript”>
function createRequestObject
() {
var ro;
ro =
(window.
ActiveXObject) ?
new ActiveXObject
(“Microsoft.XMLHTTP”) :
new XMLHttpRequest
();
return ro;
}
var http = createRequestObject();
function sndReq(action) {
http.open(‘get’, ‘rpc.php?action=’+action);
http.onreadystatechange = handleResponse;
http.send(null);
}
function handleResponse() {
if(http.readyState == 4){
var response = http.responseText;
var update = new Array();
if(response.indexOf(‘|’) != -1) {
update = response.split(‘|’);
document.getElementById(update[0]).innerHTML = update[1];
}
}
}
</script>
The first function createRequestObject() just sets up the Ajax and then creates an instance of this request object call ‘http’. That is pretty much just a standard opener for using Ajax.
The next function ‘sndReq’ is the main meat of this ajax request. It passes in the number of the window the user clicked in and assigns it to ‘action’ and then runs the PHP script ‘rpc.php?action=+action’ which will add the current window number to the cookie of visited windows.
Finally the ‘handleResponse’ function is there just for error handling-it returns from the rpc.php file which number was added and whether it was successful. It can then display that on the page for testing purposes.
The PHP script requested from AJAX (rpc.php)
This script is probably the easiest out the lot! It takes the window number passed in from the javascript using GET and checks again if there is a cookie called ‘seen’ and creates one if it doesn’t exist, or adds the passed in window number onto the string in the cookie, and then rewrites that cookie. The ‘echo foo’ parts are just for error handling and testing.
<?
session_start();
$num=
($_REQUEST[‘action’]);
if (isset($_COOKIE[‘seen’])){
$session=$_COOKIE[‘seen’];
$together=$session.“,”.$num;
setcookie(“seen”,$together, time()+3600);
//echo "foo| already session: $num";
}
else{
$expire=60*60*24*30;
setcookie(“seen”,$num, time()+$expire);
//echo "foo| no session";
}
?>
And that’s about it! It may seem incredibly complicated for something as silly as an advent calendar, but, outside of Flash, this was probably the easiest way to do it!
I understand that was pretty awful to follow, so worry not! I have included all the source files below. I’ve even got instructions!
- Create a folder on your website called whatever you want (mine was advent).
- Download and Extract the files in calendar1.zip file to that folder
- Create a folder called ‘images’ in that folder too(i.e advent\images)
- You can edit and change the bg.jpg file to whatever image you want-although keep the size at 1024×545 pixels.
- You can edit hbg.jpg too which is the header image of that page
- Create 24 images of whatever size you want(up to about 1024×768 pixels) and name them 1.jpg through to 24.jpg. Place these in the images folder.
- Create thumbnails of these images and call them t1.jpg through to t24.jpg. The thumbnail size has to be 120×180 pixels.Place these in the images folder.
- In index.php (from about line 183) edit all the descriptions to match the images for that particular number. Edit the ‘description here’ part.
- In thickbox.js edit search for any URL that is ‘http://www.is.stir.ac.uk/advent/’ and replace it with the URL of your advent calendar.
- Upload everything and cross your fingers!
Not sure if that was a very helpful post or not..sorry! But the end result is pretty good.
Ours is here: Try it out, all windows are accessible until the end of the month, and then you have to do it properly in December!
http://www.is.stir.ac.uk/advent/
Possible improvements: Use a MySQL database as the backend for organising the images. Plus actually randomly inserting the images every time too.
Creating an online advent calendar with PHP/Javascript/Ajax
**Skip to bottom if you just want the source code and instructions**!
As the festive season approaches, everyone in Britain looks forward to an advent calendar. Actually correction. Everyone looks forward to eating the chocolate from their advent calendar.
At work, I got asked to make an interactive online advent calendar to highlight some of the wonderful historic items in our Library Archive. I had a quick browse of the web to see if anyone else had done something similar, but the closest was some horrific html page from about 1995. Suffice to say, starting from scratch was the only option.
I first thought about what exactly people enjoyed about advent calendars and how that could be recreated digitally:
With digital chocolate entirely unsatisfying, it was down the the other things. I needed a advent calendar that would have this functionality:
With these in mind, I set about thinking about the easiest way to achieve these:
Combining JQuery thickbox, with some PHP scripting and cookies should make this crazy crazy dream (!) a reality.
First the layout. I decided on using a simple table to hold all the ‘windows’ in the advent calendar. I could have used DIVS and CSS(remember kids: Tables are a big no no for anything but tabular data, especially layout), however, it was pretty much tabular data I was using so decided to stick with tables.
I created simple content DIV with the background image as an attractive winter scene as the ‘front’ of the advent calendar:
background: url(bg.jpg) top left no-repeat;
width: 1024px ;
margin-left: auto ;
margin-right: auto ;
height:680px;
}
And then placed a table with 8 columns and 3 rows(to make the 24 windows) into this DIV. I styled the cells of the table with a background colour that was semi-transparent(solid block when mouse over), and randomly placed numbers into the cells.
/* Fallback for web browsers that doesn’t support RGBa */
background: url(tp.png);
height:180px;
width:125px;
font-size:55px;
color:#000000;
text-align:center;
padding:0px;
margin:5px;
filter: expression((runtimeStyle.backgroundImage != ‘none’) ? runtimeStyle.filter = ‘progid:DXImageTransform.Microsoft.AlphaImageLoader(src=’+currentStyle.backgroundImage.split(‘\”‘)[1]+‘, sizingMethod=scale)’ : runtimeStyle.filter,runtimeStyle.backgroundImage = ‘none’);
}
td:hover{
background-color:#000000;
height:180px;
width:125px;
font-size:55px;
color:#ffffff;
text-align:center;
}
I also then downloaded and installed thickbox for the images to appear in:
<script type=“text/javascript” src=“thickbox.js”></script>
Now I had the basic layout, I had to think about the best way to prevent people clicking on the image before the time was right, but also I had to ensure that any windows that had been opened before would stay open on any subsequent visists. To do this, I decided to just create one big PHP function to do it all. Below I’ll go into detail about this function, but to call it, I put placed the call in the table cell.
http://www.is.stir.ac.uk/libraries/collections/anderson/LA307.php “);?></td>
The above code calls the function ‘check’ and passes in the number of the window and a brief description of the image that will appear(this is needed for thickbox creation).
The function
The first step was to create a cookie and set it to expire a long time in the future, in this case, 30 days. I used PHP cookies to check for a cookie called ‘seen’ and create one if it doesn’t exist:
if (isset($_COOKIE[‘seen’])){
$session=$_COOKIE[‘seen’];
//echo "cookie is".$session;
}
else{
$expire=60*60*24*30;
setcookie(“seen”, “”, time()+$expire);
//echo "session is nowhere";
}
The main guts of the main function had two major operations:
To check which windows the user had opened before, I first got the cookie and assigned it to a variable called $session;
if (isset($_COOKIE[‘seen’])){
$session=$_COOKIE[‘seen’];
//echo "sesis".$session;
}
else{
$session=$_COOKIE[‘seen’]=“”;
}
I then got the current day of the month as a number, and the month number(i.e 15th Dec would be 15 and 12):
$month=date(“n”);
After this I needed to see what days the user had already seen before. The way I had been mainting the cookie was to have the windows(i.e days) that the user had already opened, seperated by a comma. So if a user had opened days 1-5, the cookie would contain: “1,2,3,4,5″. To seperate the contents of this cookie, I simply use the PHP command ‘explode’ with a comma to split up that string of numbers and place it into an array:
This now gave me my visited windows in an array called $array. All I had to do now was check that the number on the advent calendar was allowed to be clicked on(i.e the day has already passed), and that the user had clicked on it before or not.
if ($num<=$day){
if (in_array($num, $array)) {
$insert=“<img src=’images/t$num.jpg’ alt=’thumbnail for $num’ style=’width:120px;height:180px;margin:0px;padding:0px;’/>”;
}
else{
$insert=$num;
}
echo ‘<a href="images/’.$num.‘.jpg" title="’.$blurb.‘" class="thickbox" onclick="sndReq(\’‘.$num.‘\’)">’.$insert.‘</a>’;
}
else{
echo (“$num”);
}
}//month !=12
else{
echo (“$num”);
}
Let’s break that down a bit:
The first thing I’m doing here is checking that the month is December to make sure no one can access any of the windows before then:
Next, I’m checking to make sure that the window number(which is passed into the function, along with a blurb about the image that will be displayed) is less than or equal to the current day. This is the check to make sure that the user is allowed to click on the number.
After this, I need to do a check to see if the user has actually clicked on the window before, and if they have, they need to be presented with a thumbnail of the larger image they see in the thickbox when they click on the window. To do this, I’m simply checking to see if the passed in number ($num) exists in the array that was created from the cookie. It assigns a string to the variable $insert that either just has the number as a clickable link, or displays a thumbnail of the image if it has been clicked on before(i.e it was in the cookie). The thumbnail image is called t+window number.jpg. After it does this check it will print on the page either the thumbnail image or just the clickable number. Both link to the same place, it’s just whether it displays the number of the window or the thumbnail image.
$insert=“<img src=’images/t$num.jpg’ alt=’thumbnail for $num’ style=’width:120px;height:180px;margin:0px;padding:0px;’/>”;
}
else{
$insert=$num;
}
echo ‘<a href="images/’.$num.‘.jpg" title="’.$blurb.‘" class="thickbox" onclick="sndReq(\’‘.$num.‘\’)">’.$insert.‘</a>’;
Each link has a class as ‘thickbox’ that will open the image in a new thickbox on that page along with the description which is the ‘title=’ in the link.
You’ll noticed an ‘onclick’ action that takes place when the user clicks on the window link. This is to use Ajax to silently record the window number that the user had clicked on to the cookie of visited windows. Let’s take a look at this:
The AJAX bit
The onclick=”sndReq(\”.$num.’\')” calls a javscript function that passes in the number of the window the user just clicked on. This goes to some Ajax that then runs a PHP script to add that clicked on number to the cookie:
function createRequestObject() {
var ro;
ro = (window.ActiveXObject) ? new ActiveXObject(“Microsoft.XMLHTTP”) : new XMLHttpRequest();
return ro;
}
var http = createRequestObject();
function sndReq(action) {
http.open(‘get’, ‘rpc.php?action=’+action);
http.onreadystatechange = handleResponse;
http.send(null);
}
function handleResponse() {
if(http.readyState == 4){
var response = http.responseText;
var update = new Array();
if(response.indexOf(‘|’) != -1) {
update = response.split(‘|’);
document.getElementById(update[0]).innerHTML = update[1];
}
}
}
</script>
The first function createRequestObject() just sets up the Ajax and then creates an instance of this request object call ‘http’. That is pretty much just a standard opener for using Ajax.
The next function ‘sndReq’ is the main meat of this ajax request. It passes in the number of the window the user clicked in and assigns it to ‘action’ and then runs the PHP script ‘rpc.php?action=+action’ which will add the current window number to the cookie of visited windows.
Finally the ‘handleResponse’ function is there just for error handling-it returns from the rpc.php file which number was added and whether it was successful. It can then display that on the page for testing purposes.
The PHP script requested from AJAX (rpc.php)
This script is probably the easiest out the lot! It takes the window number passed in from the javascript using GET and checks again if there is a cookie called ‘seen’ and creates one if it doesn’t exist, or adds the passed in window number onto the string in the cookie, and then rewrites that cookie. The ‘echo foo’ parts are just for error handling and testing.
session_start();
$num=($_REQUEST[‘action’]);
if (isset($_COOKIE[‘seen’])){
$session=$_COOKIE[‘seen’];
$together=$session.“,”.$num;
setcookie(“seen”,$together, time()+3600);
//echo "foo| already session: $num";
}
else{
$expire=60*60*24*30;
setcookie(“seen”,$num, time()+$expire);
//echo "foo| no session";
}
?>
And that’s about it! It may seem incredibly complicated for something as silly as an advent calendar, but, outside of Flash, this was probably the easiest way to do it!
I understand that was pretty awful to follow, so worry not! I have included all the source files below. I’ve even got instructions!
Not sure if that was a very helpful post or not..sorry! But the end result is pretty good.
Ours is here: Try it out, all windows are accessible until the end of the month, and then you have to do it properly in December!
http://www.is.stir.ac.uk/advent/
Possible improvements: Use a MySQL database as the backend for organising the images. Plus actually randomly inserting the images every time too.