Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Wednesday, December 19, 2012

Timer Chaining in JavaScript

Only recently, I was working on a project where I had to implement a feature that is usually implemented using gif. What I had to do was to cause 4 images -  lets say 1, A, B, C overlayed on each other to display sequentially. And then, after the first set of 4 images have been displayed, have a similar sequence repeat, but with only the first image changed, i.e. 2, A, B, C. And then the third set - 3, A, B, C.

Now, since the sample that I had to replicate was made in gif, I presume that creating such an image using an image editing software is pretty easy. My task was to replicate this effect using pure javascript. Moreover, since it was only in the development phase, I had to design for flexibility, since requirements can change at any moment of time. Thankfully, for me, designing for flexibility is a huge turn on. Albeit inititally difficulty, the immense amout of satisfaction that you gain out of it when you see the requirements change and be able to tell your clients that you can implement the changes in like 10 seconds is totally worth the time and energy that you put in during the initial development phases.

For my experiment, the flexibility that I had to incorporate was to be able to change the duration for which each of the 4 images can be displayed if the requirements changed. Had it been a gif file, it wold have been an easy task, just change the time in the application and then it would be ready. Show the client, and if its not what he/she wants, then redo the same.

I wanted to achieve something similar in JavasScript. However instead of a tool I wanted to create a system wherein you can programmatically configure the time duration for each image and then automatically have the effect ripple throughout all the sequences of images.

Also, instead of restricting the system to that of 4 images, I wanted it to be extensible such that it would be able to incorporate any number of images that could be overlaid on top of each other. Also, I wanted the system to behave in a way that incorporates a slightly different functionality - not be restricted to images being overlaid.

So, ultimately, after thinking about all the flexibility that I wanted to incorporate into the system, it turned out that what I wanted to create was a system of timers such that each timer could be chained to each other yet they would be oblivious to characteristics of the next timer. Also, these timers would have a feature that would let them bind the timer ending function for the next timer without knowing what the function does. And the beauty would be that each of these functions can be chained to an infinite level.
So, how did i proceed to make such a system.

First things first.
I designed the system as a phase based system. Since I had 4 images in my sequence, I created a object that saved the properties of 4 phases and references to the functions that would be invoked on the terimination of each function. I called this object a phasedTimeout object, which is essentially nothing but a nested object.

The first thing that I did was - created an object that contains all the values for which i want each of the phases to execute.

var settings = {
  duration1:2000, //Millisecond duration for the first timer
  duration2:300, //Millisecond duration for the second timer.
  duration3:300, //Millisecond duration for the third timer.
  duration4:300, //Millisecond duration for the fourth timer.
 };


In the next part, I define the different phases, and the functions that can be executed at the end of each phase.

var phaseTimeouts =  {
  'phase1':
   {
    duration:settings.duration1,
    end : function(currentPhaseId){
     console.log('Ending phase : '+ currentPhaseId);
    }
   }
  ,
  'phase2':
   {
    duration:settings.duration2,
    end : function(currentPhaseId){
     console.log('Ending phase : '+ currentPhaseId);
    }
   }
  ,
  'phase3':
   {
    duration:settings.duration3,
    end : function(currentPhaseId){
     console.log('Ending phase : '+ currentPhaseId);
    }
   }
  ,
  'phase4':
   {
    duration:settings.duration4,
    end : function(currentPhaseId){
     console.log('Ending phase : '+ currentPhaseId);
    }
   }
 }


And then, finally on window loading, ( because it was part of my requirement to do all of this only after the images on the page have loaded), i created a function that chains together the different phases.

var timeOutSetter = function(){
  
   //Call the terminating function of the previous phase
   phaseTimeouts['phase'+currentPhaseId].end(currentPhaseId);
   
   //If there is anything left in phaseTimeouts array
   //create a new timer and update the new timerId
   var nextPhaseKey = 'phase'+(currentPhaseId+1);
   if(phaseTimeouts[nextPhaseKey]){
    currentPhaseId++;
    console.log('Entering Next Phase : ' + nextPhaseKey);
    currentTimerId = setTimeout(timeOutSetter,phaseTimeouts[nextPhaseKey].duration);
   }
  };


The above function does nothing but chains the different timers together by using the settings from the phaseTimeouts object. The variable phaseTimeouts is a misnomer since it captures more than just the timeout, and can perhaps be used to bind extra functionality.

For my experiment, I toggled the visibility of different images inside the 'end' function of each of the phases. But the fact that  you can have any number of phases and that each phase has a different function that handles the phase end that is independent of each other makes it all the more useful.

Below is the piece of code in its entirety


$(function(){

 var settings = {
  duration1:2000, //Millisecond duration for the first timer
  duration2:300, //Millisecond duration for the second timer.
  duration3:300, //Millisecond duration for the third timer.
  duration4:300, //Millisecond duration for the fourth timer.
 };
 
 var phaseTimeouts =  {
  'phase1':
   {
    duration:settings.duration1,
    end : function(currentPhaseId){
     console.log('Ending phase : '+ currentPhaseId);
    }
   }
  ,
  'phase2':
   {
    duration:settings.duration2,
    end : function(currentPhaseId){
     console.log('Ending phase : '+ currentPhaseId);
    }
   }
  ,
  'phase3':
   {
    duration:settings.duration3,
    end : function(currentPhaseId){
     console.log('Ending phase : '+ currentPhaseId);
    }
   }
  ,
  'phase4':
   {
    duration:settings.duration4,
    end : function(currentPhaseId){
     console.log('Ending phase : '+ currentPhaseId);
    }
   }
 }
 
 //Once all the contents of the window finishes loading, start the slideshow
 $(window).load(function(){
  
  var currentPhaseId = 1;
  var currentTimerId = 0;
  
  var timeOutSetter = function(){
  
   //Call the terminating function of the previous phase
   phaseTimeouts['phase'+currentPhaseId].end(currentPhaseId);
   
   //If there is anything left in phaseTimeouts array
   //create a new timer and update the new timerId
   var nextPhaseKey = 'phase'+(currentPhaseId+1);
   if(phaseTimeouts[nextPhaseKey]){
    currentPhaseId++;
    console.log('Entering Next Phase : ' + nextPhaseKey);
    currentTimerId = setTimeout(timeOutSetter,phaseTimeouts[nextPhaseKey].duration);
   }
  };
  
  var currentTimerId = setTimeout(timeOutSetter,phaseTimeouts['phase1'].duration);
  
 });
 
});


Decoupled designs can be so addictive, is'int it?

Signing Off
Ryan


Monday, December 10, 2012

Handling Page Unload Using JavaScript

Recently for one of my projects, I was working on trying to implement some functionality wherein if the user tried to leave web page by any other means other than submitting a form, (s)he would be prompted for confirmation. It was part of one of the research experiment surveys that I was designing. So, if the user left the page, we would simply discard the user's responses as invalid because partial responses are of no use to do any meaningful analysis.

Apparently, there are plenty of ways in which a user can close a webpage - the back button, the close button, or maybe some other gestures that I might be unaware of that are present in some of the newer web-browsing applications/devices.

What I found interesting was that there is a very simple and convenient way to check when a page is being 'unloaded' from a browser window. Javascript lets you bind a neat little handler to the 'window.onbeforeunload' property which tells the runtime that a web page is going to be unloaded.

Being a jQuery fanatic, I usually tend to use jQuery for all such stuff, since it makes maintenance a far easier task than writing pure JavaScript. So, my jQuery instincts told me to use the new on method to bind an event handler to the event. And it did work pretty good. All I did was this -

window.onbeforeunload = function(){ return "Are you sure 
you want to leave the page?"; };

Oh, I am sure that message looks familiar on many marketing sites. You can be assured that I am not creating one more such website. In fact, even the message that I displayed was  something completely different. This is just meant to be a sample.

Easy peasy, and that works. Now, the issue comes when the user actually submits the form. The issue is that this function fires if the user leaves the page in any way, which does make a lot of sense, because after all, the user is leaving the page.

However, what I did not want was for the function to fire when the user submitted the form. So, what did I do? I just created a submit handler for my form and then tried to unbind the event handler using the off function of jQuery.

Neat as it may sound, that did not work. I am still not sure why. However after going through a couple of posts wondering what I had done wrong, it dawned on me that a better way to handle this feature was to both bind and unbind an event handler for this function directly using pure JavaScript.

So, this is what i eventually ended up doing
 //For binding
 window.onbeforeunload = confirmExit;
 function confirmExit()
 {
  return "Are you sure you want to leave this page?";
 }
 
 //For unbinding
 $('#myForm').submit(function(event){
  window.onbeforeunload = null;
 });

And that's pretty much all it took to create a page that warns the user before (s)he accidentally (or intentionally) attempts to leave a web page.

Also, after completing my piece of code, i stumbled across this jQuery unload function, that I beieve pretty much does the same thing.

Signing Off
Ryan

Monday, June 25, 2012

jQuery makeArray And Array Lengths

Today I just came to know about a pretty cool thing when i was going through the documentation of the jQuery.map function. Now, the jQuery makeArray function is pretty useful because it can convert objects into arrays. But there is one restriction, your objects need to be array like objects. And what are array like objects? Array like objects are objects that have a length property. And I think that it would be safe to presume that he most common array like object known to mankind is the arguments object that is available in javascript functions.

Well, arrays in JavaScript are pretty cool because you can just remove elements from the end of an array by doing a very simple thing. Modifying the length property of the array. For example, lets say that you have an array

var myArray = [1,2,3,4,0,0,0];


Now you want to keep only the first four elements. What do you do? You simply change the lenght of the array to 4. And voila you're done. While that's cool, I was hoping that if you want to delete elements from the beginning of the array, you could set the length to a negative value. But sadly, that does not work :(. Well, you could always resolve to the good ol technique of using the shift() function. Or you could choose to reverse() and then pop(). Depends on your requirement.

But the interesting thing was that when using the makeArray function, if the length property is not set to a proper value, you will end up with an incorrect array. Taking this example right from the jQuery documentation page for the map function


// The following object masquerades as an array.
var fakeArray = {"length": 1, 0: "Addy", 1: "Subtracty"};

// Therefore, convert it to a real array
var realArray = $.makeArray( fakeArray )

// Now it can be used reliably with $.map()
$.map( realArray, function(val, i) {
  // do something 
});


As you see the fakeArray has a lenght property set to 1. When you invoke makeArray, you get an array containing only 1 element - [Addy]. What just happened to the second element??? It seems that the makeAray function converts the object into an array only for 'length' number of elements. Hence, when using this function, just beware of this behaviour and make sure that the lenght property is equal to the number of properties in your object (not counting the lenght property itself), or you might just be in for a little surprise! 

Signing Off
Ryan Sukale

Wednesday, January 26, 2011

jQuery : Creating a tag cloud widget

Tag clouds are pretty common these days on most of the websites that we come across. Tag clouds are useful because not only are they better organised as compared to displaying plain lists, but they also provide visual cues to the user of the frequency of the a particular keyword relative to the other keywords in the cloud.

In this post, I am going to create a simple jQuery widget to create a tag cloud.

Lets look at the requirements first
For any dom element, we need to display a list of anchor elements.
For each anchor element, the relative font size should be directly proportional to the frequency of occurence of the element.

Here is how the requirements will translate into technical terms.

  1. Create an unordered list such that each list item represents a tag.
  2. The unordered list should be placed inside the selected container.
  3. The font-size of each list item is based upon the relative frequency of the tag. The tag with the minimum frequency should have a minimum font size of 1. The Tag of the maximum frequency should have a font size of 2em.

Lets look at the HTML markup first. In fact, since this is a cloud widget, we dont actualy need anu html except for a container that can hold he contents of the cloud.


Ok, that was simple. Thats because all the logic of building the list and its corresponding elements lies in widget.

Lets start with our standard way of creating a widget

(function($){
var tagcloudPrototype={
 options:{
 },
 _create:function(){
  console.log('create');
  var widget=this;
  var $domElement=widget.element;
  var options=widget.options;
 }
};

$.widget('ui.tagcloud',tagcloudPrototype);
})(jQuery);

As can be seen in the above code, all the functionality of the widget lies in the _create function itself which will be called once during widget initialization.

Let us create a few options for the user of our widget, such as providing the css styles for the links in the cloud. our widget basically requires as an argument, an array 'tag' objects that have a particular structure. We will define the structure of the tag in the options element so that it can be configured by the user as per his requirement.

As per our design, we will require that for each tag, three things must be given

  1. name : The name of the tag as it will appear as an anchor.
  2. freq : The number denoting the frequency of the tag.
  3. uri : The uri to which the user will be redirected to once he clicks on the tag anchor.

The values in the array can be obtained via an ajax query or any other way. Here is a sample array

var cloudtags = [
   { name: "Java", freq: "50" , url:"#"},
   { name: "CSS", freq: "53" , url:"#"},
   { name: "XHTML", freq: "27" , url:"#"},
   { name: "jQuery", freq: "71" , url:"#"},
   { name: "MySQL", freq: "35" , url:"#"}
   ];

And here is our options object.

options:{
  tagStructure:{name:'name',freq:'freq',url:'url'},
  linkClass:'tag-static',
  linkHoverClass:'tag-hover',
  tags:[]
 }

As you can see, each tag in the array follows the same structure. Ill show later how you can use the widget if the names in your tag sructure are different from the default. The default are 'name','freq' and 'url'.

Now, lets see what needs to be done in the create function. Sicne we need the size of the tags to be dependent upon the value of the frequency, we will simply scale down the maximum and minimum frequeny between 1 and 2. ie. in our sample cloudtag array, the min value is 27 and the max value is 71. So, we need to use 1em as the font size of the tag with name 'XHTML' and 2em as the font size of the tag with name 'jQuery'.

Once computed, for each element in teh array, we will store the value of the fontSize as a property of that particular tag object array and then we will use it later to set the value of the font-size css property of the anchors.

Here is the code in the _create() function that we will use to scale down the frequency values and store it on the tag object.

var widget=this;
  var $domElement=widget.element;
  var options=widget.options;
  
  var tags=options.tags;
  var name=options.tagStructure.name;
  var freq=options.tagStructure.freq;
  var url=options.tagStructure.url;
  
  var max=0,min;
  $.each(tags,function(index, tag){
   max = Math.max(max,tag[freq]);
  });
  min=max;
  $.each(tags,function(index, tag){
   min = Math.min(min,tag[freq]); 
  });
  
  
  var divisionUnit=(max-min)/10;
  
  $.each(tags, function(index, tag){
   var fontUnit=Math.round((tag[freq]-min)/divisionUnit);
   tag.fontSize=(fontUnit<10)?'1.'+fontUnit+'em':'2.0'+'em';
  });

Now, I am only left with a simple task of creating a new unordered list and adding list items with anchors to it. This list item should reside in the selected container, i.e. the current dom element of the widget. Here is how we do it.

$domElement.append("
    "); var $tagList = $('ul',$domElement); $.each(tags, function(index, tag){ $tagList.append('
  • '+ '' + tag[name]+''+ '
  • '); });

    As seen above, there is nothing special going on. All i do is iterate over each of the elements of the tags array, and crete list items and anchor tags with the calculated font-size for each of the tag. Now the last thing that I would do is to apply the user specified styles to the anchors. And thats very trivial.


    $('a',$domElement).hover(function(){   $(this).toggleClass(options.linkHoverClass);
      });
    
    $tagList.addClass('tag-cloud-ul');
      $('a',$domElement).hover(function(){
       console.log($(this));
       $(this).toggleClass(options.linkHoverClass);
       
      });
    

    Here is the entire widget as one big blob!

    (function($){
    var tagcloudPrototype={
     options:{
      tagStructure:{name:'name',freq:'freq',url:'url'},
      linkClass:'tag-static',
      linkHoverClass:'tag-hover',
      tags:[]
     },
     _create:function(){
      console.log('create');
      var widget=this;
      var $domElement=widget.element;
      var options=widget.options;
      
      var tags=options.tags;
      var name=options.tagStructure.name;
      var freq=options.tagStructure.freq;
      var url=options.tagStructure.url;
      
      //Scaling down the frequency to a range of 1 to 10 and determining the font size
      var max=0,min;
      $.each(tags,function(index, tag){
       max = Math.max(max,tag[freq]);
      });
      min=max;
      $.each(tags,function(index, tag){
       min = Math.min(min,tag[freq]); 
      });
      
      var divisionUnit=(max-min)/10;
      
      $.each(tags, function(index, tag){
       var fontUnit=Math.round((tag[freq]-min)/divisionUnit);
       tag.fontSize=(fontUnit<10)?'1.'+fontUnit+'em':'2.0'+'em';
      });
      
      //Creating the unordered list
      $domElement.append("
      "); var $tagList = $('ul',$domElement); //Adding list items and anchors for each tag in the array $.each(tags, function(index, tag){ $tagList.append('
    • '+ '' + tag[name]+''+ '
    • '); }); //Styling $tagList.addClass('tag-cloud-ul'); $('a',$domElement).hover(function(){ console.log($(this)); $(this).toggleClass(options.linkHoverClass); }); } }; $.widget('ui.tagcloud',tagcloudPrototype); })(jQuery);

      Here is the CSS that I am using.

      #tagContainer{
          width:200px;
          height:100px;
          overflow:hidden;
          background-color:#6c6c6c;
         }
         
         .tag-cloud-ul{
          list-style:none;
          margin:0px;
          margin-left:10px;
          margin-top:10px;
          padding:0px;
          width:100%;
          height:100%;
         }
         
         .tag-cloud-li{
          float:left;
          padding:5px;
          height:30px;
          margin:0px;
         }
         
         .tag-static{
          text-decoration:none;
          color:white;
         }
         
         .tag-hover{
          color:blue;
         }
      

      Okey. Thats our widget, now lets see how to use it. Ill show you two ways. the first one shown here uses the default tag structure.

      var cloudtags = [
         { name: "Java", freq: "50" , url:"#"},
         { name: "CSS", freq: "53" , url:"#"},
         { name: "XHTML", freq: "27" , url:"#"},
         { name: "jQuery", freq: "71" , url:"#"},
         { name: "MySQL", freq: "35" , url:"#"}
         ];
         
         $('#tagContainer').tagcloud({tags:cloudtags});
      

      The one shown below does uses a custom structure for the tags.

      var cloudtags = [
         { tagName: "Java", frequency: "50" , url:"#"},
         { tagName: "CSS", frequency: "53" , url:"#"},
         { tagName: "XHTML", frequency: "27" , url:"#"},
         { tagName: "jQuery", frequency: "71" , url:"#"},
         { tagName: "MySQL", frequency: "35" , url:"#"}
         ];
         
         $('#tagContainer').tagcloud(
         {tags:cloudtags},
         {tagStructure:{name:'tagName',freq:'frequency',url:'url'}}
         );
      

      We're done! As simple as that! Once again, cheers to the jQuery folks!
      And of course, suggestions for improvement are most welcome :)

      Happy Programming :)
      Signing Off
      Ryan

      Sunday, January 23, 2011

      jQuery : Creating a simple table sorting widget

      In this article, I am going to create a very simple widget for sorting a html table using jQuery. In this article, we will see how to create a bit more complex widget as compared to the one that I had discussed earlier in my post jQuery : Creating a custom widget.

      I am going to call my new widget a 'tablesort'.

      First the HTML.

      My HTML table comprises of three columns, and contains a list of 4 of my favorite movies. In the first column, i provide the movie name, the second column is my own rating of the movie and the third column is the year in which the movie was released.

      Here is our table

      Favorite Movies My Rating Year Of Release
      October Sky 9.6 1999
      Forrest Gump 9.5 1994
      Matrix 9.9 1999
      Pursuit Of Happiness 10 2006


      Okey, lets us first see what features we will include in our tablesort widget.

      1. A user can should be able to make any table sortable which follows more or less the above html structure.
      2. A user should be able to specify which columns can be used as a sort criteria for sorting the rows.
      3. Sorting of both strings and numeric values should be handled. (This is a simple widget, and i am not handling sorting of complex data types like dates because date formats can vary a lot and i still need to figure out how to handle that sort of stuff. Any suggestions on how to do that efficiently would be great.)
      4. The user should be able to reverse the sorting on a particular column, when clicked upon consecutively.


      Now lets see how our formal requirements translate in technical terms.

      1. Since our table contains a 'thead' and a 'tbody', we first need a way to associate a column header with all the columns under it. i.e. Association of a 'th' element with a set of 'td' elements.
      2. Secondly, we need to provide a means for the user to specify the columns to be sorted and add the sorting functionality to only those columns. We also need to provide a visual cue to the user to identify the sortable columns.
      3. When a column header is clicked on, the data in the associated 'td' elements should be compared and used as a basis to sort the 'td' elements. Then based upon the ordering of the 'td' elements, we will update the DOM for the table and rearrange the table rows.


      I ususally create a prototype object for the widget first and then initialize the widget instead of doing both of them at the same time. Lets first begin by creating the options object

      var tablesortPrototype=(
      options:{
         header:'thead',
         body:'tbody',
         sortableColumns:[0],
         sortableClass:'sortable'
        }
      };
      

      I have explicitly created the header and body variables so as to allow the user a bit of flexibilility of using CSS selectors as well for identifying the head and body elements. The next two variables are to specify the default settings for the sortable columns. We will used a 0 based index, as is common in most javascript functions. So, if the user does not specify anything, the table will be sortable based upon the first column. The next variable is for the css class that can be used for styling the sortable column.

      Now lets do the widget initialization. The code for it is pretty simple and i will be doing it in the _create() function of the widget.

      _create:function(){
         console.log('create');
         var widget=this;
         var $domTable=widget.element;
         var options=widget.options;
         
         var $headings=$('th',options.header);
         
         //For each column index as specified in the sortable columns, add a click event handler
         //and the necessary css
         $.each(options.sortableColumns,function(index){
         
          var columnIndex=this;
          $headings.eq(columnIndex).click(function(){
           //call event handler for click event
          })
          .addClass(options.sortableClass);
          
         });
        }
      

      As seen in the above code, i have initialized a few local variables to reduce the amount of typing that i may have to do. You dont actually need to do it, but i find it pretty handy because not only does it eliminate unnecessary typing, but it also eliminates extra function calls and helps your scripts run a tad faster.

      So, what I have done in the above code is, fetch all the headers, and for each numeric value specified as in the sortableColumns variable, I add a click event handler and a css class.

      Okey, right now, our code is pretty useless without the click event handler. Now, lets create another private function _toggleSort that handles sorting of the columns. This function will handle sort toggling, i.e. ascending order and descending order for the clicked column. Here is my empty sort toggling function

      _toggleSort:function(columnIndex,srcDomHeader){}
      

      and here is how I will call it in my click event handler

      var columnIndex=this;
          $headings.eq(columnIndex).click(function(){
           widget._toggleSort(columnIndex, this);
          })
          .addClass(options.sortableClass);
      

      Okey, now that we have created our function, lets try to break down the code for adding the functionality one by one.

      First, i will declare local variables for the javascript objects the way I did so in the _create function

      var widget=this;
         var $domTable=widget.element;
         var options=widget.options;
      

      All the following code has comments that would explain what is being doe.

      //Get the column which has to be sorted, i.e. get all the td elements of that particular column
         var column=$(options.body,$domTable).find('tr>td:nth-child('+(columnIndex+1)+')');
      

      The column variable is a jQuery object. I need to extract the td objects from it and keep it in an array to allow for sorting and reverse ordering.

      //Convert the jQuery object into an array
         var columnArray=[];
         $.each(column,function(index){
          columnArray[index]=$(this);
         });
      

      In this widget, since we want the sorting to be reversed on consecutive clicks, i am going to use a small technique to save resorting every time the header is clicked. What I will do is to store a sortstatus when an unsorted column header is clicked. I will do this using the data() function of jQuery. So, if a header is clicked, and it does not already have the sortstatus value or if it is set to false, we will sort the data. If the value is set to true, then it indicates that this is a consecutive click, and all we need to do is to reverse current order of the rows.

      But what this also means is that when a column header is clicked upon, i must clear the sortstatus on the other column headers so that they can be resorted when clicked upon.

      This is how I do it

      //Get the heading
         var $currentHeading=$(srcDomHeader);
         
         if($currentHeading.data('sortstatus')){
          //If the column is already sorted, just reverse the rows
          columnArray.reverse();
         }
         else{
          //If not already sorted
          
          //Clear the sort status on all the other columns
          $currentHeading.siblings().data('sortstatus',false);
      
      //More code for sorting goes here
      }
      

      Once in the else, my next task will be to identify the data types for the columns. As mentioned earlier, i will handle only string and numeric values here. I save the identified datatype as a property on the columnArray variable itself.

      //Determine the datatype for the column(whether string or numeric)
          $.each(columnArray,function(index){
           if(isNaN($(this).text())){
            columnArray.dataType='string';
            return false;
           }
          });
          
          if(columnArray.dataType!='string'){
            columnArray.dataType='number';
          }
      

      My next task is to sort the data, based upon the datatype for the data in the column. So, in the following code, i will cast the data to numbers wherever applicable, and then sort the 'td' elements.

      //Sort the array using Arrays.prototype.sort by passing a custom function
          columnArray.sort(function(a,b){
           var value1='';
           var value2='';
           if(columnArray.dataType=='string'){
            value1=$(a).text();
            value2=$(b).text();
           }
           else{
            value1=parseFloat($(a).text());
            value2=parseFloat($(b).text());
           }
           return (value1<value2)?-1:(value1==value2?0:1);
          });
      

      Once this is done, my column array now contains the selected 'td' elements in a sorted order.

      Now i must add the sorting status to the header

      //Set the sort status on the current column heading, 
          //which can be used later to toggle the sorting
          $currentHeading.data('sortstatus',true);
      


      All i now need to do is to manipulate the rows of the respective 'tr' elements for the sorted 'td' elements.

      //Append the rows to the table body for each td, thereby sorting them
         $.each(columnArray,function(index){
          var column=$(options.body,$domTable).append($(this).parent());
         });
      

      Once that is done, i can safely creae my widget with the following code

      $.widget('ui.tablesort',tablesortPrototype);
      

      Here is the code for the entire widget as one big blob!

      (function($){
       var tablesortPrototype={
        options:{
         header:'thead',
         body:'tbody',
         sortableColumns:[0],
         sortableClass:'sortable'
        },
        _create:function(){
         console.log('create');
         var widget=this;
         var $domTable=widget.element;
         var options=widget.options;
         
         var $headings=$('th',options.header);
         
         //For each column index as specified in the sortable columns, add a click event handler
         //and the necessary css
         $.each(options.sortableColumns,function(index){
         
          var columnIndex=this;
          $headings.eq(columnIndex).click(function(){
           widget._toggleSort(columnIndex, this);
          })
          .addClass(options.sortableClass);
          
         });
        },
        _init:function(){
         console.log('init');
        },
        _toggleSort:function(columnIndex,srcDomHeader){
         
         var widget=this;
         var $domTable=widget.element;
         var options=widget.options;
         
         //Get the column which has to be sorted, i.e. get all the td elements of that particular column
         var column=$(options.body,$domTable).find('tr>td:nth-child('+(columnIndex+1)+')');
         
         //Convert the jQuery object into an array
         var columnArray=[];
         $.each(column,function(index){
          columnArray[index]=$(this);
         });
         
         //Get the heading
         var $currentHeading=$(srcDomHeader);
         
         if($currentHeading.data('sortstatus')){
          //If the column is already sorted, just reverse the rows
          columnArray.reverse();
         }
         else{
          //If not already sorted
          
          //Clear the sort status on all the other columns
          $currentHeading.siblings().data('sortstatus',false);
          
          //Determine the datatype for the column(whether string or numeric)
          $.each(columnArray,function(index){
           if(isNaN($(this).text())){
            columnArray.dataType='string';
            return false;
           }
          });
          
          if(columnArray.dataType!='string'){
            columnArray.dataType='number';
          }
          
          //Sort the array using Arrays.prototype.sort by passing a custom function
          columnArray.sort(function(a,b){
           var value1='';
           var value2='';
           if(columnArray.dataType=='string'){
            value1=$(a).text();
            value2=$(b).text();
           }
           else{
            value1=parseFloat($(a).text());
            value2=parseFloat($(b).text());
           }
           return (value1<value2)?-1:(value1==value2?0:1);
          });
          
          //Set the sort status on the current column heading, 
          //which can be used later to toggle the sorting
          $currentHeading.data('sortstatus',true);
          
         }
         
         //Append the rows to the table body for each td, thereby sorting them
         $.each(columnArray,function(index){
          var column=$(options.body,$domTable).append($(this).parent());
         });
        }
       };
       
       $.widget('ui.tablesort',tablesortPrototype);
       
      })(jQuery);
      
      

      Here is how I set up my tablesort widget on my table

      $(function(){
         $('#movies').tablesort({sortableColumns:[0,1]});
        });
      

      Yay! Now we have a very very simple table sorter in less than 100 lines of code. jQuery makes it so easy!

      Try out the code on your own table or on the table that I showed earlier, click on the column headings and see the effect. Of course, if there is a bug, let me know. If not, I would welcome suggestions on how this can be enhanced, or improved, or simplified.

      After all, we all love a KISS(Keep It Simple, Stupid)!

      Happy Programming :)
      Signing Off
      Ryan

      Thursday, January 13, 2011

      Using Struts 2 with JSON and jQuery

      It took a decent amount of time to figure out how to set up struts 2 with JSON. and how to extract the data using jQuery. So, i thought that i'd better make a note of the stuff i learned and just restate the rules, few as they are, so that me or someone else can cross verify them when writing code.

      There are a few things that need to be done in order to use JSON with struts 2. Basically, struts provides you with a few result types. For JSON, you will require a new Result Type, because, obviously, since the response is a JSON response, you dont have a page to redirect to.

      So, first you need to download the JSON plugin, if you already dont have it in your struts download. As usual, keep it in the lib folder of your application.

      The struts 2 JSON plugin allows you to create an action that can be serialized into a JSON object. Ok, what that means in basic terms is that in the response that is sent back to the client, the response is the Javascript object that represents the Action class, and the attributes of the javascipt object are actually named after the public getter methods of the action. If the value of any getter method returns a null, the value of the javascript attribute will be null and vice versa.

      The plugin not only handles basic types but also complex types like lists and arrays. We will see a code snippet shortly.

      First things first. Lets see what needs to be done for setting up our action for JSON.

      Keep the json plugin jar in your lib directory.
      In struts.xml, create a new package that extends json-default. If you want to use an existing package, you can simply use a comma separated value for the package names as the value of the extends parameter of the package tag. That is what I will be doing here. (TIP : json-default package extends struts-default.)
      Specify the result type of your action class to be 'json'

      Thats pretty much all you need to do to get things going from the struts configuration perspective.

      The json-default package contains an interceptor and the result type configuration for JSON requests and responses.

      Now lets get to the code.


      1. From the browser perspective : jQuery
        jQuery allows you to issue an ajax request that expects a JSON object as a response by the getJSON method. Like all other ajax requests, the syntax for making the call is the same. You need to pass the url, a javascript object representing the form parameters, and a function that will be invoked upon the return of the invocation. In the returned function, the data that is returned from the server can be treated as a JSON object.

      2. From the server's perspective : Struts 2 
        All you need to do is to create instance variables and respective getter and setter methods for variables that need to be accessed via javascript. Once in the execute method, you can simply set the values of these instance variables. Then the action need to be configured to return a json object in the struts configuration file.


      The point to be noted here is that all the variables that have a setter can be set to the values as received by the form parameters. And all the variables that have a getter method can be retrieved in the client javascript code.

      In the following code sections, we will see how we can not only handle simple data types, but also, lists and maps as JSON objects.

      First the HTML. This is just an ordinary form that contains nothing but a text field for the user to enter a name. The struts action that we will write will just be used to say Hi to the user.



      The form id is introForm. Lets handle the submit event of this form in the code to return false, since we do not want to be going anywhere when the user submits. All the action must stay on this page itself.

      $(function(){
      
       $("#introForm").submit(function(){
       
        return false;
      
       });
       
      });
      

      So, now that we know that the action will stay here, what we need to do is serialize the form inputs and issue a request to the server with the form inputs. But before we do that, we must first create the action class and then configure the action and its url in the struts configuration file. So, lets jump towards the server code for once.

      Creating the action class is as simple as it has ever been. Since this is a demo, I have created a few instance variables of type List and Map and will populate some dummy values in them so that they can be retrieved using javascript later. Also note that for all my instance variables, I have created getter methods so that their values can be retrieved.

      public class AjaxActions extends ActionSupport{
      
          private String name;
          private String greeting;
          private List countryList;
          private Map countryMap;
      
          public String sayHi(){
              
              greeting="HI " +name;
      
              countryList=new ArrayList();
              countryList.add("US");
              countryList.add("UK");
              countryList.add("Russia");
      
              countryMap= new HashMap();
              countryMap.put("US",1L);
              countryMap.put("UK",2L);
              countryMap.put("Russia",3L);
      
              return ActionSupport.SUCCESS;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public String getGreeting() {
              return greeting;
          }
      
          public void setGreeting(String greeting) {
              this.greeting = greeting;
          }
      
          public List getCountryList() {
              return countryList;
          }
      
          public void setCountryList(List countryList) {
              this.countryList = countryList;
          }
      
          public Map getCountryMap() {
              return countryMap;
          }
      
      }
      

      So, basically what i have done here in the sayHi() function is to initialize an instance variable call greeting, that says hi to the user. Then i populated a dummy list with the names of a few countries. Then i populated a dummy map with the country codes of those countries. My objective is to fetch the greetig, the list and the map on the action from the javascript code.

      In the struts configuration file, the following lines would be sufficient to configure the JSON action.

      
          
              
                  
                      
                  
      
          
      
      

      Now my server side code is ready.

      Getting back to the javascript code, I am simply going to print the values on the firefox console, you can choose to do whatever you feel like!

      $(function(){
      
       $("#introForm").submit(function(){
        
        var formInput=$(this).serialize();
        
        $.getJSON('ajax/sayHi.action', formInput,function(data) {
         
         $('.result').html('' + data.greeting + '
      ');
      
         $.each(data.countryList,function(index, value){
          console.log("value " + value);
         });
      
         $.each(data.countryMap,function(key, value){
          console.log("key "+ key + ", value " + value);
         });
        });
      
        return false;
      
       });
       
      });
      


      That does it! Last but not the least, many thanks to the programmers to write such a easy to use plugin. Kudos to all of you!

      Happy Programming :)
      Signing Off
      Ryan

      Monday, January 3, 2011

      jQuery : Binding events to dynamic DOM elements

      Today in this blog post am going to discuss about a simple way of binding events to a DOM structure, especially one that changes dynamically.

      Binding events to jQuery is simple. All that you need to do is use the bind function to bind a DOM element to a given event or to use the various alias functions like click, dblclick etc etc.

      One of the major advantages that jQuery offers is the easy manipulation of DOM objects. That means, you can easily create, add or delete DOM elements on the fly and insert them into the page. However, doing this has its quirks as well when it comes to event binding. Lets take an example.

      Consider the following HTML snippet in your page.

      1_c1
      1_c2
      2_c1
      2_c2


      Let us assume that I want to add a sibling div to the div with class "parent2" whenever a child is clicked upon. Doing that is very simple. Here's how I would do it initially.

      $(".child").click(function(){
           var newSibling = '
      new_child
      '; $(this).parent().append(newSibling); });

      Well, that solves our purpose. But there is one small problem. As you see, the new div that i inserted into the DOM has a class attribute with a value "child". So, i should presumably expect that if the user clicks over the newly inserted div element, the click event handler should be triggered. Unfortunately for us, that does no happen.

      It seems like the event handlers are bound to the DOM elements statically. i.e. Once the DOM is built, the selectors do not bind the same event handlers to newly introduced elements.

      Now that poses a serious problem, because conceptually, it seems like the events should have been bound. So, how do we go about it?

      Event bubbling to the rescue!

      We know well that events in javascript are bubbled upwards in the DOM structure. This feature enables us to solve the problem of event binding for dynamically created elements.

      What we are going to do is to bind the click event handler to the parent div of the "child" elements. So, whenever a child element is clicked upon, the parent div gets notified due to event bubbling. In the click handler, you can identify the source DOM element that was clicked by using the value of event.target, where event is the argument that is passed to the click handler. Once we have got a handle on the source DOM element, the job's done! So, if you add a new DOM element to the parent, since the click handler is bound to the parent, you can always be sure that the new child element will also be clickable because the actual handler function is on the parent element.

      Here is the code.

      $(".parent1").click(function(event){
           var $source = $(event.target);
           var newSibling = '
      new_child
      '; $($source).parent().append(newSibling); });

      Pretty simple eh? Ya, I know its a dumb example, but, I guess simple is always better for demonstration purposes.

      Oh, and I could have used $(this).append(newSibling); instead of $($source).parent().append(newSibling);, because it suits our requirement, but I was just trying to be a bit verbose!

      Thats all for now folks!

      Happy Programming :)
      Signing Off
      Ryan

      Saturday, November 6, 2010

      Finding elements using jQuery - Part 3

      In this part of the series, I will be discussing a few more ways that are offered by jQuery to traverse siblings of an element.

      The methods that we are going to discuss in this post are

      prev()
      prevAll()
      prevUntil()
      next()
      nextAll()
      nextUntil()

      All these functions provide us with a way to traverse the siblings of a given DOM element. Lets see some examples.

      • 0
      • a
      • b
      • c


      The prev() function selects the DOM element that lies immediately above the current element. So, if we were to apply the prev function to our list item3, it would select the list item 2. However, if you want to select the previous item only if it matches a particular criteria, then you can pass a selector to the prev() function. Note tat the selector function DOES not select the first matching previous sibling. Instead it first select the previous sibling, and then applies the test criteria to it.

      $(".item3").prev().addClass("highlighted");
      

      The above code would select the second list item and would add a class called highlighted to it.

      Now lets see this

      $(".item3").prev(".other").addClass("highlighted");
      

      The above code would select the previous element and then check if it has a class called other. If not, as it in in our case, it will return an empty jQuery object(note that an empty jQuery object is not a null object. Its just like an empty array). The addClass function is called on the empty array and hence has no effect.

      Now lets take a look at the prevAll() function

      $(".item3").prevAll().addClass("highlighted");
      

      This function, when called without the arguments will select all the previous siblings of the current element. In our case, all list items except list item with clas .item3 will be selected.

      When passed an argument, only those previous siblings are returned that satisfy the test criteria.

      $(".item3").prevAll(".item1").addClass("other");
      

      In this case, only the previous siblings that have the class as 'other' will be returned by the selector.

      Sometimes you have a requirement of selecting the first previous sibling that matches your selection criteria. For example in the below DOM structure, i have 2 list items with a class called 'other'. Suppose that i am traversing from list item 'item3' and i need to get the item having the html value of 'a'.i.e. the second list item.

      • 0
      • a
      • b
      • c

      Here is how it can be done

      $(".item3").prevAll(".other").eq(0).addClass("highlighted");
      

      As you see, the prevAll function will traverse in upwards in the DOM for all the siblings. Since you need the first match, you select the element 0 of the matched set and apply your style class to it.


      Another very useful function is the prevUntil() function. this function is used to select all the DOM siblings, before the current element, until an element is found that satisfies the search criteria.


      $(".item3").prevUntil(".other").addClass("highlighted");
      

      So, in our example, all the previous list items of class 'item3' will be selected until a list item with class 'other' is found on the DOM. This function, when called without the selector argument, works the same way as the prevAll function. So, it would be pointless to call this function without the selector argument.

      The other functions - next(), nextAll() and nextUntil() work in exactly the same way as their counterpart function, apart from the fact that instead of selecting the previous siblings, these functions work on the siblings that follow the currently selected element.

      These six functions make traversing in a given sibling structure pretty easy.

      Happy Programming :)
      Signing Off
      Ryan

      Friday, November 5, 2010

      Finding elements using jQuery - Part 2

      Today in this post, I am going to pick up from where i left off in the previous post where I discussed about how to use contexts and the usage of the find function and the children function.

      Now, lets take a look at another cool way in which a jQuery allows us to traverse the DOM.

      One of my favorite functions is the siblings function. This function, as the name suggests allows you to get the siblings of a the current element. For example, suppose you have a unordered list and you need to change the css of a particular list item on mouse hover to indicate that it is being highlighted, but at the same time, you will also need to clear the other list items that were previously hovered over. As is common in jQuery, there is more than one way to achieve this. Lets check out two different ways in which this can be done.

      • a
      • b
      • c


      In order to achieve the effect that we desire, we can simply make use of the hover function.

      $(".level1>li").hover(
           function(){$(this).addClass("highlighted")},
           function(){$(this).removeClass("highlighted")}
          );
      

      But lets make things a bit more complicated. Suppose instead of simply highlighting the current li, your currently highlighted elements also need to print the information of the previously highlighted element. In this case, the hover function wont suffice. I know example sound a bit silly, but its a silly silly world out there, and requirements can be bizarre and unpredictable. In the next snippet, i am just going to demonstrate how the siblings function can come to the rescue when we need to countenance such requirements.

      I am just going to print the value of the previously selected item on the firefox console(ah, yes I am a firefox fan, if you haven't already noticed that by now, although I occasionally use chrome as well for my adventures). Note that I will be printing it when my mouse pointer is over the new element, instead of when the mouse is coming out of the previous element.

      $(".level1>li").mouseover(
           function(){
            var prevHovered = $(this).siblings(".highlighted");
            if(prevHovered.length!=0){
             console.log("prev html : "+prevHovered.html());
             prevHovered.removeClass("highlighted");
            }
            $(this).addClass("highlighted");
           }
          );
      


      As you see in the above code, I use the mouseover function to handle the selection of the element. The siblings function will select all the siblings of the ul, but the important thing to note here is that the current element is not returned in the selected set. So, all you have is a set of siblings of the current element. You can narrow down the search by providing an optional selector to the siblings function so that only those siblings that match the selected criteria will be returned in the set. However, if you don't pass any argument, all the siblings will be returned.

      All the above code did was to select the previously selected element, check if it was not null. It its not, print the html of that element on the console and remove the highlighting from that element.

      Easy stuff.

      But I mentioned before that I used the mouseover function instead of the hover function. The hover function can take either 1 or 2 arguments as callbacks that can be used to call your function. If only one argument is sent, it will called on both of the mouseover and mouseout event. If you provide two functions as arguments, the first will be used for a mouseover and the second will be used for the mouseout event.

      I figured, instead of having an empty mouseout, i'd rather use the mouseover function since it is more natural to our requirement in this case. However you can replace the mouseover function with the single argument hover function in the above code, and it would still work the same.


      There's more from where that came from. Stay tuned!


      Happy Programming :)
      Signing Off
      Ryan

      Thursday, November 4, 2010

      Finding elements using jQuery - Part 1


      Today in this blog post I am going to discuss a few ways in which we can find DOM elements using jQuery.

      We all use jQuery selectors in order to select elements to work upon. Most of our selectors are usually based upon the id or the class or some other attribute, and sometimes even the structure of the elements being selected. However, apart from these selectors, jQuery also allows you to select elements in a completely different way, like all the siblings of an element, all the children of an element. It also allows you to search within the context of another element.

      Lets see what I mean by that. Consider the following DOM structure.

      • a
      • b
      • c
        • c1
        • c2

      As seen in the structure, i have one main ul which has three li elements. this ul acts as the main container. The third li element in the main container in turn has another ul which has three li subelements.

      For both the ul elements, the li elements have been assigned classes pertaining to their location in the list. So, we ended up with a total of four li elements having the same class for the li element- item1 and item2.

      Now let us see the various ways in which we can select the different elements in this structure.

      As usual, we will be writing all our code in the jQuery onload function which is as follows.

      $(function(){
      //All our code goes here. });

      Lets assume that we want to color all the elements that have the class 'item2' within our ul that has a class 'container'

      There are actually three ways to achieve this.
      Here is the first.

      $(".container .item2").css({"background-color":"blue"});
      

      This way is simple, and we use normal css selectors to find all the sub elements in the DOM under our .container that have a class named as .item2. This, in our case,would set the background color of both the li elements that have the 'item2' class.

      Now lets see a second way to do it.

      $(".item2",".container").css({"background-color":"blue"});
      

      This is also equivalent tot the previous snippet. This selector makes use of "search context". A search context is nothing but the context in which the elements will be searched. So, if i were to read out the selector expression, it would be read something like this

      'Select all the elements that have a class called item, that exist inside the element that has a class called container'

      This means that the first argument that is passed to the selector is the actual search expression, whereas the second argument that we passed to the selector becomes the context of our search.

      It also means that when we don't pass the second argument, the entire DOM structure is searched by default.

      Here is the third way to do it.

      $(".container").find(".item2").css({"background-color":"blue"});
      

      In the above code, we are using the find() jQuery function to find the elements. If i were to read it aloud, it would be read as

      'Select the elements with a class called container first, and inside all those selected containers, select the elements that have the class called item2.'

      Sometimes, if your classes are unique, you may not feel the need to find elements using the context. Or, in many cases, it is possible to find the elements using a normal selector that would traverse the entire DOM. Why use contexts and confuse things?

      However, when your structure becomes complicated, it may come in extremely handy to use contexts to find elements. Because, when you find using contexts, jQuery has to traverse fewer DOM elements to get the elements you desire to search, thereby saving you time and improving overall performance.

      Sometimes, it it better to make use of a context when you already have a part of the search for the context already done for you.

      For example, let us assume you register a click function for your container. And inside the click function, you need to do the same thing that we did above.

      Here is how it could be done in the normal way

      $(".container").click(function(){
      $(".item2",".container").css({"background-color":"blue"});
      });
      

      But there is one thing to be noticed here. We are already in side the click handler of the container. That means, jQuery has already searched the DOM for our container. Then why do we need to again ask jQuery to search the DOM for the container? Instead, we can make use of the current context, and simply search for the item we want.

      Here is how it can be done.

      $(".container").click(function(){
      $(".item2",$(this)).css({"background-color":"blue"});
      });
      

      The context in a click handler is determined by the value of the 'this' variable. So, finding elements can become easier for jQuery if you just know when and were you can reduce the lookups that jQuery has to do, by making use of an existing context.

      That's all for now. I shall discuss more ways of finding elements using jQuery in future posts.
      Till then, cya!

      Happy Programming :)
      Signing Off
      Ryan

      Wednesday, November 3, 2010

      jQuery : Creating a custom widget


      Today, in this post, I am going to discuss how to create a custom widget using jQuery.

      Lets begin with the definition of a widget.

      A widget in jQuery means nothing but a function that can be called on a jQuery selector that modifies the behaviour of all the selected elements by attaching data to the selected elements and maintaining individual state for each of these elements.

      The important point to be noted here is the "state keeping" that is associated with each selected element. This is what makes the difference between a jQuery plugin and a jQuery widget. A widget can be considered to be an advanced form of a plugin.

      Widgets can be of several types. For example, you may create a widget that simply formats the data in an element. Or you may create a widget that is closely associated to the structure of a html snippet, because it uses the html structure to create its layout. for e.g the "tabs" widget.

      In this post, I am going to create a very basic widget, that actually does nothing useful. My objective here is to write a basic skeleton structure to create a widget that you can replace anytime with your own functionality.

      Our prerequisites :

      Download the jQuery UI plugin. This plugin contains the javascript files that are necessary to create a widget. Thats because the widget function is available to us via the UI plugin. Of course that does not mean that you can only create UI related widgets using this plugin. You are always only limited by your imagination.
      You can download it from here. For the examples in this post, all you need is the four components that fall under the "UI Core" category. We will only be dealing with the basic stuff here. Come back when you are done.

      Okey, now that you're back, I want to ensure two things before we begin.
      1. You have extracted the zip file in some arbitrary location on your disc. lets call it "jQueryUI". This folder should contain the "js" folder and the "development-bundle" folder. We shall be using he "jQueryUI" as the root directory where we would be creating our html page in which we would be using jQuery.
      2. You create a page called widgetExperiment.html in your root directory.


      In the head section of your html page, include the following lines of code.

      
        
        
        
        
      


      These are the scripts that we need to refer to in order to create our custom widget. As you can see, the version numbers of your script files may differ based upon when you are actually reading this blog. Just go to the appropriate directories and replace the src file names in the script tag with the proper file names.

      Now, we are all set to crate our first jQuery widget.

      Lets start with the standard "onload" function in jQuery.

      $(function(){
      //All our Code goes here
      });
      

      When creating a widget, the first thing that we need to do is to create an object that represents the functions and the data of our widget. This object acts as a prototype for our widget data. The purpose of this object is to encapsulate the functions and the properties that will be associated with each selected element returned by the jQuery selector expression.



      var myPrototype={
            options:{level:1},
            setLevel:function(level){this.options.level=level;},
            getLevel: function () { return this.options.level; },
            _init: function() { this.setLevel(this.getLevel());}
           };
      

      As can be seen above, I named my prototype object "myPrototype". Inside my prototype, i have a few functions and an object called "options".

      There are two things that you need to know about the properties that are created inside a widget.
      The function names that begin with an underscore are private. i.e. these functions cannot be called from outside of the widget.

      All the data, pertaining to the state of the widget should be kept in an internal object called "options".
      An instance of the widget is created for each element returned by the selector. The options object ensures that for each instance of the widget that is created, the properties remain private to that particular instance.

      Initialization of your widget if required, must take place in the _init function. You can also create a destroy function to perform any cleanup when your widget instance is destroyed. These functions are called automatically and are part of your widget lifecycle.

      As seen in the code, for my widget, i created a private property called "level" and two "getter/setter" functions to manipulate this property. The getter/setter functions are public by virtue of not starting with an underscore.

      Calling these functions are not done in the usual manner. We shall see how to invoke these public functions once we have created the widget.

      Creating a widget is very simple. All that you need to do is to associate your prototype object with a name and pass it to the jQuery widget function. Here is how it is done

      $.widget("ui.myWidget",myPrototype);
      


      The jQuery widget plugin function is used to create your widget by assigning it a name in the namespace "ui.myWidget" and then passing the object that we use as the prototype object in the second parameter.
      Although the namespacing is "ui.myWidget", your widget is simply named myWidget and that is what your plugin function will be called.

      Associating your widget with an element is a complete no brainer. For example, the following code associates all my divs on the page with my widget. (you dont want to associate all your divs with a widget unless ur a total nut, or if you are testing something like the way I am doing now)

      $("div").myWidget();
      

      Now lets see how to use our newly created widget. If you remember, when creating the widget, we declared a property called "level" that set to an initial value of 1 in the widget. Now we are going to write a simple click handler for our divs that sets the value of the level and prints it on the console.

      $("div").click(function(){
            
            $(this).myWidget("setLevel",4);
            
            console.log($(this).myWidget("getLevel"));
            
           });
      
      


      In the following example, notice how we called the public functions getLevel and setLevel. Also notice how we passed a parameter to the setLevel function of our widget. The first argument is treated as the function name and the second argument onwards are treated as the arguments for the function being invoked.

      Here is the entire code in a single snippet


      var myPrototype={
            options:{level:1},
            setLevel:function(level){this.options.level=level;},
            getLevel: function () { return this.options.level; },
            _init: function() { this.setLevel(this.getLevel());}
           };
           
           
           $.widget("ui.myPrototype",myPrototype);
           
           
           $("div").myPrototype();
           
           $("div").click(function(){
            
            $(this).myPrototype("setLevel",4);
            
            console.log($(this).myPrototype("getLevel"));
            
           });
      


      Well, that seemed pretty easy, didn't it? But our widget lacks one important thing that we would need to do in most of our widgets. That is, to access the current element to which the widget is attached, inside the widget. You cannot use "this", because inside the object, the keyword "this" represents an instance of the widget. The actual element associated with the object is accessed via "this.element", which is a jQuery object representing the dom element.

      So, if you were inside the init method and you wanted to print the value of the id of your selected element, that could easily done by the writing the following lines in the init method

      console.log("inside init : "+this.element.attr("id"));
      

      So, thats one more thing settled.

      Lets add a little more 'dummy' functionality to our code by allowing it to interact with the mouse. In order to allow your widgets to interact with the mouse, you need to create your widgets in a slightly different way.

      Here is how you created the widget in the normal case ;

      $.widget("ui.myWidget",myPrototype);
      

      And here is how you will create it when you need mouse interaction

      $.widget("ui.myWidget",  $.ui.mouse,myPrototype);
      

      Once you have done that, you can need to override a few functions to handle mouse related events on your widget. But before that you should call the _mouseInit and _mouseDestroy methods in the _init and destroy methods of your widget respectively.

      Here is the code in all its mighty form!

      var myPrototype={
            options:{level:1},
            setLevel:function(level){this.options.level=level;},
            getLevel: function () { return this.options.level; },
            _init: function() { this._mouseInit();},
            
            
            destroy: function() {
             this._mouseDestroy();
             return this;
            },
            
            _mouseCapture: function(event) {
             console.log("inside capture: x("+event.pageX +") y("+event.pageY+")" );
             return true;
            },
            
            _mouseStart: function(event) {
             console.log("inside start: x("+event.pageX +") y("+event.pageY+")" );
             return true;
            },
            
            _mouseDrag: function(event) {
             console.log("inside drag: x("+event.pageX +") y("+event.pageY+")" );
             return false;
            },
            
            _mouseStop: function(event) {
             console.log("inside stop: x("+event.pageX +") y("+event.pageY+")" );
             return false;
            }
            
           };
           
           
           $.widget("ui.myWidget",  $.ui.mouse,myPrototype);
      

      I hope this bare bones example comes in handy to get you started quickly on creating simple widgets.

      Thats all for now folks!

      Happy Programming :)
      Signing Off
      Ryan

      Monday, September 13, 2010

      A sample paint application using jQuery

      In today's post, I am going show how one can associate mouse events to an html element using jQuery. JQuery allows us to bind a large number of events to objects fetched by using a jQuery selector.

      The following is the list of events that are recognized by jQuery :
      blur, focus, focusin, focusout, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error.

      Binding events to jQuery usually means making the selected Dom Object aware of the event and take necessary actions based upon it.

      The primary function that jQuery uses to perform these binding is called (surprisingly!) the bind() function.

      The syntax of the bind function is simple. For a given selected set of jQuery object, you indicate the function that needs to be called when a particular event takes place on that DOM object.

      So, basically, its an eventname - handler function() duo. Occasionally, you may also need to pass additional parameters to the handler function. That is done by passing a map of the parameters in the arguments of the bind function.

      Following is the basic syntax of the function.

      .bind( eventType, [ eventData ], handler(eventObject) )
      


      However, for most tasks, you would be using the following version of the function

      .bind( eventType, handler(eventObject) )
      

      In this post, I am going to create a simple application that acts like a very very primitive version of MS Paint. Here's the basic idea : -

      I am going to create a div, that will act as a canvas. Using the mouse, the user should be able to draw curves on the screen as he drags the mouse on the canvas, just like the way we do using pencil and paper. The only difference is that instead of the pen, you use the mouse, and instead of the paper, you have a div(to which I will assign appropriate dimensions) on which to draw.
      To make things a bit more interesting, (just a bit more), i will allow the user to choose a color for the paintbrush.

      The body of my html page has 2 parts- the canvas, and the color palette.

      green
      blue
      red
      black


      The div that I am going to use as a canvas has been given an id if "canvas".
      The palette contains four div's that act as buttons that can be used to select the color. The content of the 4 div's is nothing but the name of the color the div represents.

      So, here's the basic plan to achieve what i want to do : -
      1. Track the movement of the mouse, the moment it is pressed, and stop tracking it the moment it is released. This will be achieved by binding appropriate handlers to the mousedown event, the mousemove event and the mouseup event.
      2. When the mouse is being dragged on the canvas, i need to create a dot at the position of the mouse. In this example, i am going to create a 4 pixel dot. This dot is nothing but an span element having absolute positioning. A new span will be created for every position that my mouse cursor moves over in the area described in my canvas.


      Here is the basic CSS that I will be using to achieve the desired layout.

      .canvasStyle{
       width:500px;
       height:500px;
       background-color:#cfcfcf;
       float:left;
      }
      
      .dots{
       width:4px;
       height:4px;
       position:absolute;
      }
      
      
      .palleteStyle{
       float:left;
       padding:10px;
       position:relative;
       text-align:center;
      }
      
      .colorChooser{
       border:solid 1px #000000;
       -moz-border-radius: 8px;
       -webkit-border-radius: 8px;
       border-radius: 8px;
       margin:5px;
       padding-bottom:8px;
       width:100px;
       height:12px;
      }
      


      The css is pretty simple. I have a class 'canvasStyle' to define the layout of my canvas. Then I have a class 'dots' to define the layout of my dots. Then a class 'palleteStyle' to define the layout of my color palette. And then a class 'colorChooser'.

      Now lets talk about the javascript. All my code is in the jQuery onload function. Since this is the only functionality of my sample web page, I have taken the liberty to use global variables within this function. You may have to use a more structured approach if you want such functionality to coexist with your existing code. (making a widget would be a good idea, but we shall see about that later)

      The only global variable that i am going to use here is the color of the brush. Initially, I set it to black. Here is the code for it.


      $(function(){
       var bkcolor="black"; 
      });
      

      Now, the first thing i need to do is to bind the mousedown and mouseup event of the canvas to a particular function in which i will do my additional tasks.

      Fortunately, the code for binding mouse events in jQuery is simpler than you can even imagine.

      $("#canvas").bind('mousedown',function(event){
       
      });
      
      
      $("#canvas").bind('mouseup',function(){
       
      });
      

      The next thing that i need to do is to enable the user to click on any of the four div's on my color palette and be able to set the color variable based upon his selection. Since the color is the same as the inner html of the div's the code to set the color of the brush is pretty trivial. (dont look at me like that, i did this to make my life a bit easier!)

      $(".palleteStyle").click(function(event){
       $target=$(event.target);
       bkcolor=$target.html();
      });
      

      In the above code, as you can see, instead of binding a separate function to each of my coloring div's, i chose to bind the click event handler to the parent container, i.e. my color palette. Inside the event handler, I determine the target of the click by using the 'target' property of the event object that jQuery allows me to pass to my event handling function. Once I get hold of my target, all I need to do is to set the value of the global variable to the html of the selected div.

      Well, now there are only 2 important things remaining. Binding and unbinding the mousemove event on mouseup and mousedown. The other thing is to add a span to my canvas at the position of the mouse cursor.

      First things first. Lets see the code for binding and unbinding the mousemove events.

      $("#canvas").bind('mousedown',function(event){
       $(this).bind('mousemove',function(event){
               //some code goes here
       });
      });
      
      
      $("#canvas").bind('mouseup',function(){
       $(this).unbind('mousemove');
      });
      


      Well, quite simple eh? Ok then, lets move on to the next task of adding a span.

      For adding a span, we first need to identify the position of the mouse cursor. This task will be handled in the mousemove handler function. As you can see above, the handler function takes and event variable as an argument. This variable can be used to identify the x and y coordinates of the mouse as and when it moves.
      the X and y coordinates of the mouse can be retrieved from the pageX and pageY attributes of the event object. After that, all we need to do is to add the span to the dom inside the canvas. We achieve that by using the append() function. That said, the following code should be easily understandable.

      $("#canvas").bind('mousedown',function(event){
       $(this).bind('mousemove',function(event){
        var dot ="";
        $(this).append(dot);
       });
      });
      

      The above code simply creates a span and sets the left and right css attributes to the pageX and pageY. And of course I set the background color to the bkcolor global variable.


      Now, just to add a little more spice, ill change the visual appearance of the color selection div's based upon the color the represent. Here's the code for it.

      $(".colorChooser").each(function(){
       $this = $(this);
       var bkcolor=$this.html();
       $this.css({"background-color":bkcolor,"color":"white","opacity":"0.8"});
      });
      

      Ya, I know, I unnecessarily made it fancy, but believe, you got my point.

      Time to see the entire javascript for this example in one huge chunk. So, here goes nothing : -

      $(function(){
       var bkcolor="black";
       $("#canvas").bind('mousedown',function(event){
        $(this).bind('mousemove',function(event){
         var dot ="";
         $(this).append(dot);
        });
       });
          
       
       $("#canvas").bind('mouseup',function(){
        $(this).unbind('mousemove');
       });
       
       $(".colorChooser").each(function(){
        $this = $(this);
        var bkcolor=$this.html();
        $this.css({"background-color":bkcolor,"color":"white","opacity":"0.8"});
       });
       
       $(".palleteStyle").click(function(event){
        $target=$(event.target);
        bkcolor=$target.html();
       });
      });
      

      Thats pretty much it takes to make something as simple as a bare bones paint application.
      Here is the screenshot of how it looks in Chrome on my pc.



      Forgive me, my calligraphy with the mouse ain't so good. But its kinda fun, especially if it can be done in a browser! And of course, jQuery makes it unbelievably easy :)

      Cheers!
      Happy Programming :)
      Signing Off
      Ryan