Site Moved

This site has been moved to a new location - Bin-Blog. All new post will appear at the new location.

Bin-Blog

Ajax Tutorial Part 2 - Traditional Feedback Form

Before building the Ajaxed form, we will create a traditional version of it. This way we will make sure that our application will degrade gracefully. Graceful Degradation means that, whenever you decide to include features designed to take advantage of the latest technologies, you should do it in a way that older browsers can still allows access to the basic functionality of our page.

In our application, graceful degradation means that we should make sure that the form works even if the user have turned off their javascript or if they are using an old browser.

Required Database Structure

Before anything, we create the database required for storing the data. I am intensionally keeping the database as simple as possible. Feel free to make more complicated databases when trying this example on your own. For the basic functionality we just need to save two fields - the email field and the comment field. I also added an id and a time field.


CREATE TABLE `feedback` (
  `feedback_id` int(11) NOT NULL auto_increment,
  `feedback_email` varchar(255) NOT NULL default '',
  `feedback_comment` mediumtext NOT NULL,
  `feedback_time` datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (`feedback_id`)
) TYPE=MyISAM AUTO_INCREMENT=8 ;

(X)HTML Markup for the Feedback Form

Before any coding, we will create the required form. NOTE: The following form is a visual demo only - it will not save your comments. That is because the current server does not support PHP.

A simple feedback form




The above form is create using the code...


<form name="feedback_form" id="feedback_form" method="POST" action="save_data.php">
<fieldset>
<legend>A simple feedback form</legend>

<div id="form_elements">
<label for="comment">Comments</label><br />
<textarea name="comment" id="comment" rows="5" cols="30"></textarea><br />

<label for="email">E-Mail</label><br />
<input name="email" id="email" type="text" /><br />

<input name="action" id="action" type="submit" value="Submit" />
</div>

</fieldset>
</form>

PHP Code that Updates the Table

Keep this in the 'save_data.php' - the file that is given as the action of the above form. This is the file that does the server side duties - like saving the user entered values to the database


<?php
include('./connect.php'); //Connect to the database.

//Insert data into our database
mysql_query("INSERT INTO feedback(feedback_email,feedback_comment,feedback_time) 
 VALUES('$_REQUEST[email]','$_REQUEST[comment]',NOW())") or die("Cannot save : " . mysql_error());

?>
<html>
<head>
<title>Feedback Received</title>
</head>
<body>
<h1>Feedback Received</h1>

Thank you for your intrest - we will look into your comment as soon as possible.
</body>
</html>

Our traditional feedback form is functional now. In the next section we will see how to add the 'Ajax Effect' to this page.

[This the second part of a three part series on Basic Ajax progamming. See part one - A Gentle Introduction to Ajax]
UPDATE : The third part of the Tutorial - Ajax Feedback Form is now available.

Read More...

Google Pages - Free Web Hosting Service from Google

Google Pages is yet another new feature from Google. This is basically a much more user friendly version of Geocities or Tripod. Google Pages allows you to host your pages on the web free of charge.

Screenshot of Google pages

I have already tried out the service. The editing is in WYSIWYG mode by default - and it looks quite nice. The web interface is almost as good as some WYSIWYG programs. For all you advanced users out there, there is also an option to edit the HTML of the site. It also have a 'Upload Stuff' feature that can be used to, eh..., upload stuff. I have not yet tried out all the features but I will try it as soon as I get some free time.

Be warned though - the site is in Beta - so expect many errors. I encountered some of these when I tried it out. Don't trust it with important data - there is a chance for data loss. Just make sure you have a backuped version on you local system and you should be fine.

Sreekanth, a colleague of mine have been playing around on this service much longer than me - he have already created a site that would pass of for a real site. Try it out - if you have a Gmail Id, you are already registered for the service.

Read More...

jx Ajax Library - in Object Notation

I have been planning to rewrite the jx Ajax Library using object notation. I have been putting it off for some time now. But after reading Dustin's JSON article I could not wait any longer. So here it is...

////////////////////////////////// jx Library ///////////////////////////////////////////
var jx = {
 http : false, // We create the HTTP Object
 
 //Create a xmlHttpRequest object - this is the constructor. 
 getHTTPObject : function() {
  var xmlhttp;
  
  //Use IE's ActiveX items to load the file.
  if(typeof ActiveXObject != 'undefined') {
   try {
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
   } catch (e) {
    try {
     xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (E) {
     xmlhttp = false;
    }
   }
  //If ActiveX is not available, use the XMLHttpRequest of Firefox/Mozilla etc. to load the document.
  } else if (XMLHttpRequest) {
   try {
    xmlhttp = new XMLHttpRequest();
   } catch (e) {
    xmlhttp = false;
   }
  } else {
   xmlhttp = false;
  }
  return xmlhttp;
 },

 //This function is called from the user's script. It will take a url and an optional callback function.
 // Then it will read the url file, expecting a json string. Once the file is loaded, the script
 // will phase the json string using 'eval' and call the user defined callback function with this
 // array as the argument.
 //Arguments - 
 // url - The url of the serverside script that is to be called. Append all the arguments to 
 //   this urls as GET params - like get_data.php?id=5&car=benz
 // callback - Name of the function that should be called once the data is ready. If a callback
 //   function is not given, then the default function 'jx_processResults' will be used.
 // type - The return type for this function. Could be 'json' or 'text'. If it is json, the string will be
 //   'eval'ed before returning it. Default:'text'
 getData : function (url,callback,type) {
  if(!this.http) return;
  if(!type) var type = "text"; //Default type is 'text'
 
  this.http.open("GET", url, true); 
 
  //Call a anonymous function when the state changes.
  this.http.onreadystatechange = function () {
   if (jx.http.readyState == 4) {//Ready State will be 4 when the document is loaded.
    var result = "";
    if(jx.http.responseText) result = jx.http.responseText
    
    //If the return type is json, we have to 'eval' the string before returning it.
    if(type == "json" || type == "j" || type == 1) {
     //Careful - if the responseText is not a valid json string, 
     //  there will be javascript errors here.
     result = eval(result); //Yes, I know I used eval - its JSON, stupid.
    }
    
    if(callback) {
     callback(result); //Give the data to the user defined function.
    } else { //If there is no user defined function...
     //Call a predefined  function with the result.
     if(jx_processResults) jx_processResults(result);
    }
   }
  }
  this.http.send(null);
 },

 init : function() {
  this.http = this.getHTTPObject();
 }
}

//Call it like this.
function init() {
 jx.init();
 jx.getData("data.php",function (data) {
  alert(data);
 },'t');
}
window.onload=init;

If you have any opinions about how to improve it, please feel free to use the comment area below. I major drawback of this system over the 'global function' approach is that this method needs to call the jx.init() at the beginning of the code. In the previous method, we could call the jx_getData function without any other code. If you have any suggestions on how it can be avoided, they are very welcome.

Read More...

A Gentle Introduction to Ajax

What is Ajax?

Ajax or Asynchronous JavaScript and XML enables the programmer to execute a server-side script without refreshing the page.

Example...

A simple form.

Traditional method

The user enters the comments and email and then clicks the submit button. The browser sends the entered data to the server-side script through the post or get method. When this is done, the browser will call the server-side script(for example a PHP page) by loading that page in the browser. This page will save the data to a database and display a 'Thank You' message in the browser.

The problem with this approch is that the users loses some time waiting for another page to load. The page cannot save the entered data without loading the PHP file.

The flow of data in the Traditional method

Ajax Method

Here when the user clicks the Submit button, a javascript function is called which loads the server-side script in the background. The user does not see it being loaded. Instead the JavaScript will immediatly remove the form from the page and show a 'Thank you' message dynamically - without reloading the page.

The flow of data in the Ajax method

Algorithm

if (user hits the submit button) {
 comment = (user submitted comment)
 email = (user's email id)
 
 //Happens in Background
 CallPage("save_comment.php?comment=" + comment + "&email=" + email);
 
 //User sees this...
 Remove(form)
 Display("Thank you for your comment.")
}

Application

The given example was for a simple application. In more advaced uses, the result generated by the called server-side script will be taken and used in the page. Some applications that would be impossible without Ajax are...

Examples of use of Ajax

Problems

  • Breaks the Back button
  • Works only on the latest browsers
  • Harder to make and maintain
  • Goes against user expectations
  • Assesibility issues

[This the first part of a three part series on Basic Ajax progamming]
UPDATE : Part 2 of tutorial is now available.
UPDATE : The third part of the Tutorial - Ajax Feedback Form is now available.

Read More...

jx Ajax Library Code (Beta Version)

Remember the Ajax Library I talked about in the last post? I am releasing the first version of its code. This is a beta version and the final one will be much different - but the underlying concept will be the same...

////////////////////////////////// ax Library ///////////////////////////////////////////
var jx_http = jx_getHTTPObject(); // We create the HTTP Object
//Create a xmlHttpRequest object - this is the constructor. 
function jx_getHTTPObject() {
 var xmlhttp;
 
 //Use IE's ActiveX items to load the file.
 if(typeof ActiveXObject != 'undefined') {
  try {
   xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
   try {
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
   } catch (E) {
    xmlhttp = false;
   }
  }
 //If ActiveX is not available, use the XMLHttpRequest of Firefox/Mozilla etc. to load the document.
 } else if (XMLHttpRequest) {
  try {
   xmlhttp = new XMLHttpRequest();
  } catch (e) {
   xmlhttp = false;
  }
 } else {
  xmlhttp = false;
 }
 return xmlhttp;
}

//This function is called from the user's script. It will take a url and an optional callback function.
// Then it will read the url file, expecting a json string. Once the file is loaded, the script
// will phase the json string using 'eval' and call the user defined callback function with this
// array as the argument.
//Arguments - 
// url - The url of the serverside script that is to be called. Append all the arguments to 
//   this urls as GET params - like get_data.php?id=5&car=benz
// callback - Name of the function that should be called once the data is ready. If a callback
//   function is not given, then the default function 'jx_processResults' will be used.
// type - The return type for this function. Could be 'json' or 'text'. If it is json, the string will be
//   'eval'ed before returning it. Default:'text'
function jx_getData(url,callback,type) {
 if(!jx_http) return;
 if(!type) var type = "text"; //Default type is 'text'

 jx_http.open("GET", url, true); 

 //Call a anonymous function when the state changes.
 jx_http.onreadystatechange = function () {
  if (jx_http.readyState == 4) {//Ready State will be 4 when the document is loaded.
   var result;
   if(jx_http.responseText) result = jx_http.responseText
   else result = "";
   
   //If the return type is json, we have to 'eval' the string before returning it.
   if(type == "json" || type == "j" || type == 1) {
    //Careful - if the responseText is not a valid json string, there will be javascript errors here.
    result = eval(result); //Yes, I know I used eval - its JSON, stupid.
   }
   
   if(callback) {
    callback(result); //Give the data to the user defined function.
   } else { //If there is no user defined function...
    //Call a predefined  function with the result.
    if(jx_processResults) jx_processResults(result);
   }
  }
 }
 jx_http.send(null);
}

//This is the function that is called when the javascript fetches the given url. We can put our code
//  in it.
function jx_processResults(data) {
 return;
}

We can call this script using the code

//This is the function that is called when the javascript fetches the given url. We can put our code
//  in it.
function jx_processResults(data) {
 if(data) {
  alert("The user 'binnyva' exists in the database. Please choose another username.");
 } else {
  alert("The username 'binnyva' is free!");
 }
}
jx_getData("user_exists.php?login=binnyva");

...OR...

jx_getData("user_exists.php?login=binnyva",function(data) {
 if(data) {
  alert("The user 'binnyva' exists in the database. Please choose another username.");
 } else {
  alert("The username 'binnyva' is free!");
 }
});

... OR with JSON ...

function showUser(data) {
 alert("Username : " + data['username'] +
  "\nLocation : " + data['location'] +
  "\nWebsite : " + data['website'] +
  "\nEmail : " + data['email']);
}
jx_getData("user_details.php?login=binnyva",showUser,"json");

This is a preview release - the functions are not finalized yet. I will probably put a wrapper class around it - like this...

jx = {
 "http":this.getHTTPObject();

 "getHTTPObject": function() {
  /*...*/
 }
 
 //Rest of the functions.
 /*...*/
}

If you have any suggestions, this is the best time to let me know.

Read More...

Smallest Ajax Library - jx

I am trying to create the smallest Ajax library - I call it jx. Like many other javascript developers, I hate libraries. The primary reason for this is that they are big. When ever I get I library with a functionality I need, I try to extract just the needed function for my program.

So now I am trying to create a library with just one(or two) functions so that who ever is using it will find it easy to extract just the needed functions. But my final goal is to strip away every function that is not crucial - so that the library users won't have to do it.

I have one problem however. I was hoping that I could make it simple enough to do this...
var data = jx_callScript('script.php?arg=value');

But as of yet, I am finding it impossible to do. I need at least two functions - like this.

function callBack(data) {
 /*
 ...
 */
}
jx_callScript('script.php?arg=value',callBack);

This is because of jx_http.onreadystatechange = functionName; where 'onreadystatechange' must have a function attached to it. When the browser finishes fetching the data from the server, it will call the given function. But I want to get it as a return value.

If someone knows how to get over this obstacle(or even if it possible), please let me know.

Read More...

KDE, Gnome and Nautilus

After I bought the new system, I am using Linux(Fedora Core 3) and I have not looked back once. I am configuring the OS to play according to my rules - a daunting but fun task.

KDE vs Gnome

I always used Gnome eariler because I thought KDE was very slow and bloated. But when I tried KDE on the new system, I found how to turn down all the effects that was slowing the system. Even better, I could change the appearnce of the window manager to that of Win 98 - the OS I am most comfortable with.

You can do this using this app...
KMenu -> Preferences -> More Preferences -> Desktop Settings Wizard
Or you could do it the hard way - using the preferences control panel in KDE.

Nautilus vs Konqueror

One thing I still don't like about KDE is its File Manager - Konqueror. I still prefer the simpler and much faster Nautilus. You could write some nautilus scripts to improve the functionality of nautilus - and then it is unbeatable.

Some the scripts I use are given below. To install these script, just create a file with this data, give it the permission 755 and put it in the folder '~/.gnome2/nautilus-scripts/'. Nautilus looks in this folder for all its executable scripts.

Backuper (By Me)

# Backuper V 1.00.A
# Creates a Backup of the selected file and appends a timestamp to it 
#  in the format '<Filename.ext>_Feb06_20.45.58.bak'
echo -n "cp '$1' '$1_">/tmp/backuper.sh
date "+%b%d_%H.%M.%S.bak'">>/tmp/backuper.sh
sh /tmp/backuper.sh

Open Terminal

#!/usr/bin/perl -w
# Open terminal here
#
# Nautilus script that opens a gnome-terminal at the current location, if it's
# a valid one. This could be done in shell script, but I love Perl!.
#
# 20020930 -- Javier Donaire <jyuyu@fraguel.org>
# http://www.fraguel.org/~jyuyu/
# Licensed under the GPL v2+
#
# Modified by: Dexter Ang [thepoch@mydestiny.net]
# 2003-12-08: Modified for Gnome 2.4
#  - Added checking if executed on Desktop "x-nautilus-desktop:///"
#    so that it opens in /home/{user}/Desktop

#use strict;
$_ = $ENV{'NAUTILUS_SCRIPT_CURRENT_URI'};
if ($_ and m#^file:///#) {
  s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  s#^file://##;
  exec "gnome-terminal --working-directory='$_'";
}

# Added 2003-12-08 Dexter Ang
if ($_ == "x-nautilus-desktop:///") {
  $_ = $ENV{'HOME'};
  $_ = $_.'/Desktop';
  exec "gnome-terminal --working-directory='$_'";
}

Search Here

#!/usr/bin/perl
# Nautilus script that opens the gnome-search-tool(Actions->Search for Files) tool in the
# selected directory.
# 
# Author : Binny V A
# http://www.geocities.com/binnyva
# Copied from 'Open Termianl Here' Script 

#use strict;
#use warnings;

$_ = $ENV{'NAUTILUS_SCRIPT_CURRENT_URI'};
if ($_ and m#^file:///#) {
  s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  s#^file://##;
  exec "gnome-search-tool --path='$_' --contains=";
}

if ($_ == "x-nautilus-desktop:///") {
  $_ = $ENV{'HOME'};
  $_ = $_.'/Desktop';
  exec "gnome-search-tool --path='$_' --contains=";
}
Read More...

Color Fade Effect using JavaScript

I recently created a fade effect for an element for the new version of Sudoku. I had to create the effect from scratch because I could not find any scripts in the net that matched my requirements. The result of my effort is given below. The hex2num and the num2hex functions were posted earlier.

////////////////////////////// Colour Functions /////////////////////////////////////
//Convert a hex value to its decimal value - the inputed hex must be in the
// format of a hex triplet - the kind we use for HTML colours. The function
// will return an array with three values.
function hex2num(hex) {
 if(hex.charAt(0) == "#") { 
  hex = hex.slice(1);
 }
 hex = hex.toUpperCase();
 var hex_alphabets = "0123456789ABCDEF";
 var value = new Array(3);
 var k = 0;
 var int1,int2;
 for(var i=0;i<6;i+=2) {
  int1 = hex_alphabets.indexOf(hex.charAt(i));
  int2 = hex_alphabets.indexOf(hex.charAt(i+1));
  value[k] = (int1 * 16) + int2;
  k++;
 }
 return(value);
}
//Give a array with three values as the argument and the function will return
// the corresponding hex triplet.
function num2hex(triplet) {
 var hex_alphabets = "0123456789ABCDEF";
 var hex = "#";
 var int1,int2;
 for(var i=0;i<3;i++) {
  int1 = triplet[i] / 16;
  int2 = triplet[i] % 16;

  hex += hex_alphabets.charAt(int1) + hex_alphabets.charAt(int2);
 }
 return(hex);
}

//Function that fades the color.
//Arguments...
//id  - ID of the element whose colour must be faded.
//start_hex - The initial color of the element.
//stop_hex - The final color. The element will fade from the initial color to the final color.
//difference- The colour values will be incremented by this number
//delay  - The speed of the the effect - higher delay means slower effect.
//color_background- The fade must be for the color of the element or for its background.
//      Allowed values are 'c'(Color of element) and 'b'(Background)
function fadeColor(id,start_hex,stop_hex,difference,delay,color_background) {
 //Default values...
 if(!difference) difference = 20;
 if(!delay) delay = 100;
 if(!start_hex) start_hex = "#FFFFFF";
 if(!stop_hex) stop_hex = "#000000";
 if(!color_background) color_background = "c";
 
 var ele = document.getElementById(id);
 if(!ele) return;
 var start= hex2num(start_hex);
 var stop = hex2num(stop_hex);
 
 //Make it numbers rather than strings.
 for(var i=0;i<3;i++) {
  start[i] = Number(start[i]);
  stop[i] = Number(stop[i]);
 }

 //Morph one colour to the other. If the start color is greater than the stop colour, start color will
 // be decremented till it reaches the stop color. If it is lower, it will incremented.
 for(var i=0;i<3;i++) {
  if (start[i] < stop[i]) {
   start[i] += difference;
   if(start[i] > stop[i]) start[i] = stop[i];//If we have overshot our target, make it equal - or it won't stop.
  }
  else if(start[i] > stop[i]) {
   start[i] -= difference;
   if(start[i] < stop[i]) start[i] = stop[i];
  }
 }

 //Change the color(or the background color).
 var color = "rgb("+start[0]+","+start[1]+","+start[2]+")";
 if(color_background == "b") {
  ele.style.backgroundColor = color;
 } else {
  ele.style.color = color;
 }

 //Stop if we have reached the target.
 if((start[0] == stop[0]) && (start[1] == stop[1]) &amp;& (start[2] == stop[2])) return;

 start_hex = num2hex(start);
 //Keep calling this function
 window.setTimeout("fadeColor('"+id+"','"+start_hex+"','"+stop_hex+"',"+difference+","+delay+",'"+color_background+"')",delay);
}

You can call the fade effect for an element <div id="element_to_fade">Hello World</div> using the code fadeColor("element_to_fade","#ACFF00","#0000FF",10,100,'c');. If you are feeling adventurous, try this...

function init() {
 fadeColor("element_to_fade","#0000FF","#ACFF00",10,100,'b');
 fadeColor("element_to_fade","#ACFF00","#0000FF",10,100,'c');
}
window.onload=init;
Read More...

Compressing JavaScript file on the fly using JSMin

JSMin is a Javascript source compressor created by Douglas Crockford. The PHP version of this software can be used to compress JavaScript source files 'on-the-fly' - just before serving it. This approach will save your bandwidth without the need for keeping two versions of a script - a compressed one and an uncompressed one. The main disadvantage of this approach is that it is not processor friendly.

There are many other javascript compressors available(including one written by yours truly). Some of the popular ones are given below.

The default method of compression for the JSMin is using a C program but a PHP version(text file) is also given. You can use this to compress your javascript 'live'. If you make an update to the file, you won't have to compress it before uploading it. But this method is processor expensive as some processing must be done to compress the file every time the file is requested.

To use this on your site download the PHP version of JSMin script and rename it to 'jsmin.php'. Then add the following lines at the end of the file - just above the '?>' line.


$js_file = $_GET['file'];
if(file_exists($js_file) and is_readable($js_file)) {
 header("content-type:text/javascript");
 jsmin($js_file);
}

After the jsmin.php file is configured, you can call any of your javascript script using this HTML
<script src="jsmin.php?file=your_js_file.js" type="text/javascript"></script>

Even though the 'your_js_file.js' file is not in the compressed format, it will be compressed by our script before it reaches the browser - saving your precious bandwidth.

Filed Under...

Read More...

Subscribe to : Posts