This tutorial came in order to give a response
to the different email asking me how to create a calendar similar to
the one in my home page. Many of you probably have a blog in your
sites, and this tutorial will show you how to make a calendar.
1. Introduction
This tutorial came in order to
give a response to the different email asking me how to create a
calendar similar to the one in my home page.
Many of you probably
have a blog in your sites, and this tutorial will show you how to make
a calendar which will show to the users which dates have a post
available.
1.1 What I need ?
- PHP 4.3.x
- AMFPHP installed on your server
- Flash MX 2004
- An account on blogger.com
2. Blog installation and customization
First
thing you need to have a blogger.com account. Once created the account
you can set up your server settings for the file publishing policy.
Go into Settings->Archiving as shown in the image below:
Now, make this changes:
In this way every time you create a new blog post a new file on your server will be created with a name similar to "2004_11_04_weekly.html"
All the system we are going to create will be centered on the file names!
Pay attention on the folder path where these files will be created.
3. The AMFPHP class
Ok,
now it's time to pass to the AMFPHP class installation. It will be a
very simple class with just one method for retrieving the avaialble
dates.
Ok, so create in your services default path a new PHP file DateChooser.php which will be our remoting service:
<?php
class DateChooser {
// ---------------------------------------------------------------
// First I set the Folder where all the blog html pages are stored
// Pasy attention with this. It's fundamental
// ---------------------------------------------------------------
var $base_path = "./../../blog";
// constructor
function DateChooser() {
$this->methodTable = array(
"findBlogByDatePK" => array(
"description" => "Returns list of images in album",
"access" => "remote",
"arguments" => array ("month","year")
)
);
}
// -------------------------------------
// public method
// month and year are required arguments
// -------------------------------------
function findBlogByDatePK($month,$year)
{
// create the array for avail dates
$availDate = array();
// $availDate = new myDate();
// check arguments
if(empty($month) || !is_dir($this->base_path) || empty($year)){
// return an error message
return array("error" => $_SERVER['PATH_TRANSLATED'] . $name . "is not a valid directory");
}
// open the default dir
$dir = @opendir($this->base_path);
if(!$dir){
// return error on fails
return array("error" => $_SERVER['PATH_TRANSLATED'] . $name . " cannot open selected directory");
}
while($file = readdir($dir))
{
// get month value from file name
$_month = substr($file,5,2);
// get year value from file name
$_year = substr($file,0,4);
// compare to arguments passed
if(number_format($_month,0) == number_format($month,0) && number_format($year,0) == number_format($_year,0))
{
$_date = number_format(substr($file,8,2),0);
array_push($availDate, $_date);
}
}
return $availDate;
}
}
?>
First:
<?php
class DateChooser {
// First I set the Folder where all the blog html pages are stored
// Pasy attention with this. It's fundamental
var $base_path = "./../../blog";
Remember that always your class name must be the same as your php file name!
Then var $base_path must point to the correct path of your blog html file!
You can see in this picture how are organized my directories :
In fact my service php file DateChooser has to go to twice to parent folder, then into blog folder.
function DateChooser() {
$this->methodTable = array(
"findBlogByDatePK" => array(
Inside the DateChooser constructor there is the methodtable array in which we just need to define 1 method "findBlogByDatePK" .
So, let's analyze the code of that method:
function findBlogByDatePK($month,$year)
{
// create the array for avail dates
$availDate = array();
// check arguments
if(empty($month) || !is_dir($this->base_path) ||empty($year)){
// return an error message
return array("error" => $_SERVER['PATH_TRANSLATED'] . $name . "is not a valid directory");
}
Ok, first consideration. In order to work correctly flash must pass as arguments month and year in numberic formart (remember that in flash month value starts from '0' to '11').
If these arguments are empty or if the base_path directory assigned is
not a valid dir, then return an error message.
// open the default dir
$dir = @opendir($this->base_path);
if(!$dir){
// return error on fails
return array("error" => $_SERVER['PATH_TRANSLATED'] . $name . " cannot open selected directory");
}
try to open the directory for reading, otherwise return an error message again.
while($file = readdir($dir))
{
// get month value from file name
$_month = substr($file,5,2);
// get year value from file name
$_year =substr($file,0,4);
// compare to arguments passed
if(number format($_month,0) ==number format($month,0) && number format($year,0) ==number format($_year,0))
{
$_date = number format(substr($file,8,2),0); array push($availDate, $_date);
}
}
return $availDate;
}
Now, the core of this method.
With the opened directory make a while loop and read all the files into
that path. Retrive the file name and compare it with the arguments
passed by flash
2004_11_01_weekly.html will be processed as this:
- $_month = "11"
- $_year = "2004"
then is both month and year are the same as the arguments ($month,
$year) this means that this file is what we're looking for!
Then add the date substring of this filename to the array to be
returned to flash. (We don't need to give back month and year values,
but only the date value)
In this way, an example debug withing flash should return something similar to these pictures:
In the params given to PHP: 2 means "february" and 2004 is the year.
PHP has returned an array of 2 elements: 4 and 9. This means that we
should activate only these two dates in our calendar.
4. Using the DateChooser component in Flash MX 2004
We just need the pre-installed DateChooser component in our flash movie. Nothing more.
So, drag the DateChooser component from the UI component of your Flash
mx 2004 program and give it the instancename of "calendar" .
Now
create 3 layers above the current: "AMFPHP","syles" and "listener". I
prefer to separate the different actions in different layers.
4.1 Customize the Component
In the "styles" layer just put some code for customize the component:
this.calendar.setStyle("fontSize", "10")
this.calendar.setStyle("embedFonts", false)
this.calendar.setStyle("fontFamily", "Georgia")
this.calendar.setStyle("fontWeight ", "bold")
this.calendar.setStyle("borderColor ", 0xFFFFFF)
this.calendar.setStyle("borderStyle", "none")
this.calendar.setStyle("themeColor", "haloBlue")
this.calendar.setStyle("disabledColor", 0x999999)
this.calendar.setStyle("color", 0x000000)
4.2 Add a Event Listener to the Calendar
// -----------------------
// Calendar EVENT Listener
// -----------------------
objInit = new Object();
// When month cnages
objInit.scroll = function(obj){
callServ(obj.target.displayedMonth,obj.target.displayedYear);
}
// click on a date item
objInit.change = function(obj){
var d:Date = obj.target.selectedDate
var mm = d.getMonth() + 1
mm = mm < 10 ? "0" add mm : mm
var yy = d.getFullYear()
var dd = d.getDate()
dd = dd < 10 ? "0" add dd : dd
// open the browser passing the selected date as GET param
getURL("/index.php?blogId=" add yy add "_" add mm add "_" add dd add "_weekly.html")
}
// ---------------------------------
// Make the remoting call
// ---------------------------------
function callServ(m,y){
serv.findBlogByDatePK(m + 1, y);
this.calendar.enabled = false
}
// ---------------------------
// call the service first time
// ---------------------------
callServ(this.calendar.displayedMonth, this.calendar.displayedYear);
// ----------------------
// add the event listener
// ----------------------
this.calendar.addEventListener("scroll", objInit);
this.calendar.addEventListener("change", objInit);
-------
So first we've created an Object listener "objInit" for the DateChooser Component events, and at the end we've assigned to the component itself with the command addEvetListener.
This object event has 2 methods:
- scroll: this make an action when user
click on the arrows for change the month displayed. This just call the
remoting service passing as params the month and year to be displayed
- change: a day in the compoonent has been selected. This check the date selected and compose an URL string to be passed as GetURL
The callServ function make calls the findBlogByDatePK
on the remoting service and makes the calendar disabled in the
meantime. We increase the month param by one because flash starts from
'0' to calculate month values, while the files saved in our blog
directory has the standard month values, starting fom 1 to 12.
4.3 AMFPHP services
#include "NetServices.as"
#include "NetDebug.as"
// -----------------------
// AMFPHP Object Responder
// -----------------------
myDC = {};
myDC.scope = this
// listener for findBlogByDatePK service call
myDC.findBlogByDatePK_Result = function(data){
// enable the calendar again
this.scope.calendar.enabled = true
// disabled dates array
var dRanges = new Array();
// enabled dates array - lenght 31
var eRanges = new Array(31);
for(var a in data){
// put the date available as key in the enabled dates array
eRanges[int(data[a])] = true;
}
// walk in the enabled array
for(var a = 1; a <= eRanges.length; a++){
// format a new date
var sDate = new Date(this.scope.calendar.displayedYear, this.scope.calendar.displayedMonth, int(a));
// if value is not true this date is not available
if(eRanges[a] != true){
dRanges.push({rangeStart: sDate, rangeEnd: sDate});
}
}
// apply disabled dates
this.scope.calendar.disabledRanges = dRanges;
}
// ----------------------------
// Make the Remoting Connection
// ----------------------------
if(gatewayURL == undefined){
gatewayURL = "http://localhost/flashservices/gateway.php";
}
NetServices.setDefaultGatewayUrl (gatewayURL);
conn = NetServices.createGatewayConnection ();
// select the service to be consumed
serv = conn.getService ("DateChooser", myDC);
Ok, analyze it now!
First create a default responder for any remoting call "myDC" and assign it the current scope with myDC.scope = this .
In fact we will assign this responder to the current remoting service at the end:
serv = conn. getService (" DateChooser ", myDC);
This means that all the response request to the DateChooser.php file will be redirected to the myDC functions.
This function :
myDC.findBlogByDatePK_Result = function ( data ){
will be called when the server get a result response due to a call to the remote method findBlogByDatePK. and it's in this function that we will enable/disable certain dates in our calendar.
In fact:
first create two different arrays:
var dRanges = new Array ();
the array containing all the disabled dates
var eRanges = new Array (31);
the array (lenght = 31) of all the enabled dates
Now, get all the data argument passed values and assign them as key of our eRanges array (giving them the value true)
for ( var a in data ){
eRanges[ int ( data [a])] = true ;
}
For every element of the eRanges array (31 elements... max length of a
month days), create a new Date variable and set its value corrsponding
to the key number of the current eRanges array. This means: for every
key of the eRanges arra (from 1 to 31) create a Date variables with the
data value from 1 to 31.
if the current key element, in the eRanges array (we populated it in the previoius for loop, remember?) is not true, we append this value in the dRanges array:
for ( var a = 1; a <= eRanges. length ; a++){
var sDate = new Date ( this .scope.calendar.displayedYear, this .scope.calendar.displayedMonth, int (a));
if (eRanges[a] != true ){
dRanges. push ({rangeStart: sDate, rangeEnd: sDate});
}
}
So, finally we can assign to the component the disabled dates, using a property of the component itself:
this .scope.calendar.disabledRanges = dRanges;
|