How to create a rounded corner box plugin with jQuery

Recently, we have redesigned one of our projects. The task was to make the web application to look and act more like Web2.0 app. New design looked great and surely it had lot's of rounded corners.

You can download jQuery Rounded Corners plugin.

First, rounded corners were done using CSS, but it got our code cluttered and it introduced a lot of unnecessary HTML markup. Since we had full control of our target audience's browsers and we were sure that they had JavaScript enabled browser we chose jQuery to do all the dirty work. All we have to do to define a box/table/anything to be in a rounded box is to give it a class "boxed" and the rest is done with jQuery.

Here is the final rounded corners jQuery plugin code:

(function($){
  $.fn.extend({
    box: function() {
      return $(this).each(function(){
        $(this).wrap('<div class="box"><div></div><div class="tl"></div><div class="tr"></div><div class="bl"></div><div class="br"></div></div>');
      });
    }
  })
})(jQuery);

CSS looks like this:

/* -- Rounded Box -- */ 
.box{position:relative;background-color:#eee;margin-bottom:25px;padding:10px;} 
.box .tl,.box .tr,.box .bl,.box .br{position:absolute;width:10px;height:10px;} 
.box .tl{background-image:url(images/box-tl.gif);top:0;left:0;} 
.box .tr{background-image:url(images/box-tr.gif);top:0;right:0;} 
.box .bl{background-image:url(images/box-bl.gif);bottom:0;left:0;} 
.box .br{background-image:url(images/box-br.gif);bottom:0;right:0;} 
.box .bg-white{background-color:#fff;padding:10px;}

How to set default settings in your jQuery plugins

Recently we had a post about automatically adding row count to your tables and then made a plugin out of it. We could further improve our plug-in by providing an option to let plug-in users to overwrite default setting.

For example plugin users could provide a CSS class to set to the added column or change the default "#" in the column header to some other meaningful text.

This is all possible by letting users of your plugin to provide their setting.

For example, in our table row count plugin, users could do this:

$('table').addCount({colName : 'Number'});

So this is how you do this:

$.fn.addCount = function(options) { 
  // set up default options 
  var defaults = { 
    colName:      '#', 
    colWidth:     100, 
    addCssClass:  true, 
    colClass:     'mycolumn', 
  }; 

  // Overwrite default options 
  // with user provided ones 
  // and merge them into "options". 
  var options = $.extend({}, defaults, options); 

  /* 
    If user provided only "colName" 
    option then default options for 
    other 3 variables will be added 
    to "options" variable. 
  */ 

  return this.each(function() { 
    /* Now you can use 
     "options.colWidth", etc. */ 
    console.log(options); 
  }); 
}; 

The key line here is var options = $.extend({}, defaults, options); This line merges options and defaults variables adding missing properties in options variable from defaults variable.

Here is a great example from documentation page of jQuery.extend() that gives a good example about $.extend() method.

var empty = {} 
var defaults = { validate: false, limit: 5, name: "foo" }; 
var options = { validate: true, name: "bar" }; 
var settings = $.extend(empty, defaults, options);

Namespace your JavaScript function and variable with jQuery

We all know that global variable are evil. Namespacing  your variables and methods is now considered a good practice and shows your awareness about the trends. Anyway, I thought how can I namespace my variables and methods in jQuery. Well, first off, I can easily extend jQuery with custom written plugins.

$.fn.extend({
  myNamespaced: function(myArg){
    return 'namespaced.' + myArg;
  }
});
jQuery().myNamespaced('A');
$().myNamespaced('A'); // Shorthand $()
// Outputs: namespaced.A

Now my functions are namespaced and would not conflict with any other already declared functions with the same name. This is great, but to access my functions or variables I have to call jQuery(). The code still looks like chaining not namespacing. To declare your variables or functions in jQuery namespace you can extend the core jQuery object itself using jQuery.extend() rather than jQuery.fn.extend().

$.extend({ 
  myNamespaced: function(myArg){ 
    return 'namespaced.' + myArg; 
  } 
}); 
jQuery.myNamespaced('A'); 
$.myNamespaced('A'); // Shorthand 
// Outputs: namespaced.A

As you can see, now I can call my functions and properties without parenthesis after jQuery object. Now my functions have a jQuery namespace and will not conflict with other functions that might have the same name.

TIP:
Use $.extend({}) to namespace your fields and methods.

Object-Oriented JavaScript, how to achieve public properties/fields

Recently I posted my findings about private fields in JavaScript. So this is a continuation of the post and it talks about public fields in your JavaScript code. So here is a quick example of public properties in your code:

function User() {
  // Private property
  var name = '';

  return {
    // Public property
    classVersion: '1.3',
    prevVersions: ['1.2.3', '1.2', '1'],

    setName: function(newName) {
      name = newName;
    },
    getName: function() {
      return name;
    }
  };
}
var user = new User();
user.classVersion; // 1.3
user.prevVersions; // ['1.2.3', '1.2', '1']

NOTE:
Define an object property name in your return statement and it will be accessible from outside. In other words - public field.

Public and private methods in JavaScript

I have been talking about public and private properties so far. I guess it is time for private and public methods. The idea behind is the same. To make a method public you need to define it in your return object and if you want to make it private you should declare it outside your return.

Basically:

function User() {
  // Private variable
  var name;

  // Private method
  var privateMethod = function(){
    // Access to private fields
    name += " Changed";
  };

  return {
    // Public methods
    setName: function(newName) {
      name = newName;
      privateMethod();
    },
    getName: function() {
      return name;
    }
  };
}
var user = new User();
user.setName("My Name");
user.getName(); // My Name Changed

As you can see, privateMethod and name are declared outside the return object and thus they are made private. Variables declared inside the return object are public and accessible using dot notation.

jQuery 1.2.6 and jQuery 1.3 class selector performance benchmark

Reading about the jQuery 1.3's new selector engine Sizzle and its speed improvements I thought I would do a performance comparison between jQuery 1.2.6 and jQuery 1.3. I was prepared for something good, but the test results blew my mind.

I had a page with one unordered list with 1000 items each with a class (class="1", class="2", etc).

Here is  are the tests and results:
console.time("testClass");
for(i=0;i<100;i++){
    $('.'+i);
}
console.timeEnd("testClass");
/**
* jQuery 1.2.6

1235 ms
1326 ms
1342 ms
=======
1301 ms

*/
/**
* jQuery 1.3

54 ms
52 ms
53 ms
=======
53 ms

*/

As you can see the new selector engine is freakishly fast :) Actually with this specific test it is 25 times fast. Taking into the consideration that class selection is one of the most used selectors, we can assume that our code will work considerably faster.

NOTE:
I have performed the same  tests with selection with id's. The result were exactly the same (9 ms). Taking into the consideration that both versions of jQuery use browser's built in getElementById() function for ID selections, there is not much one can do to beat that.

Working with jQuery 1.3's new Event object (jQuery.Event)

To start, in jQuery 1.3 event object has been normalized and wrapped into jQuery.Event object. As it says in the documentation: "The event object is guaranteed to be passed to the event handler (no checks for window.event required)."

Here is an jQuery.Event object overview:

  • Attributes
    1. event.type
    2. event.target
    3. event.relatedTarget
    4. event.currentTarget
    5. event.pageX/Y
    6. event.result
    7. event.timeStamp
  • Methods
    1. event.preventDefault()
    2. event.isDefaultPrevented()
    3. event.stopPropagation()
    4. event.isPropagationStopped()
    5. event.stopImmediatePropagation()
    6. event.isImmediatePropagationStopped()
Now, how to work with jQuery.Event object?

Anonymous functions that were bind to your elements will receive this new (jQuery.Event) event object and can utilize it's new attributes and methods. So your previous code will work fine (most of the time :) ).

$("a").click(function(event) { 
    alert(event.type); 
});

The fun part starts when you trigger events with jQuery.Event. You can create new jQuery.Event object and give it to the trigger()'er to trigger that event.

Example:

// Create new event object 
// the "new" is optional 
var e = jQuery.Event("click"); 

// Add additional data to pass 
e.user = "foo"; 
e.pass = "bar"; 

// Call your event 
$("a").trigger(e);

NOTE:
You don't have to use new to create a new jQuery.Event object. It is optional.

Alternative way to pass data through event object:

$("a").trigger({ 
    type:"click", 
    user:"username", 
    pass:"password" 
});

Try to play with the new event attributes and methods. You can do all kinds of fun things with them. Example: event.result, event.relatedTarget.

Pack and minimize your JavaScript code size

In pursue for my JavaScript code performance and some questions on jQuery mailing list I looked for and eventually came across some of the JavaScript code packers. Here is a list of custom JavaScript code compressors available for free.

  1. YUI Compressor (from Yahoo)
  2. JSMin (by Douglas Crockford)
  3. ShrinkSafe  (from Dojo library)
  4. Packer (by Dean Edwards)

According to general opinion of developers on the net (and jQuery official site) you should use Yahoo's YUI Compressor to compress your jQuery and JavaScript code.

How to check your JavaScript code for errors

There are times when you can't understand why your code is not doing what it's supposed to do. After killing half an hour on trying to figure out what is the problem you either give up and decide to rewrite or leave it for later. Later looking at your code you clearly see the bug and think how you couldn't you see it.

For cases like that you can use online JavaScript code validator JSLint.

jQuery and HTML image maps

Most of us don't even use image maps anymore. But occasionally, mostly when freelancing, you will need to work with the pages that were created in mid 90's and image maps where pop stars in that era. Anyway to refresh your memory here is how HTML image map looks like:

<img src="bigImage.gif" usemap="#parts" />  
<map name="parts">  
  <area shape="rect" coords="20,6,200,60" href="http://www.boo.uz">  
  <area shape="circle" coords="100,200,50" href="http://www.google.com">  
</map>

To access HTML image map area attributes and properties use something like this:

$('area').click(function() { 
    var url = $(this).attr('href'); 
    var coords = $(this).attr('coords').split(','); 

    // Your code here 

    // To prevent default action 
  return false; 
});

This is all that I have on jQuery and image maps.

How to select innermost element with jQuery

Today I was working on new category browser UI for the project I am working. I had to select the innermost element and append some more content into it. Basically, I had an HTML like this:

<div>Outermost element 
  <div>Some Text 
    <div>Evenmore text 
      <div>Who cares anymore? 
        <div>Innermost Element</div> 
      </div> 
    </div> 
  </div> 
</div>

So I needed to select the innermost div and append another div to it. There is no jQuery selector but you can use selectors that exist to achieve this goal. The innermost element would be the last div with the only-child.

$('div:only-child:last'); 

// Change background color to gray 
$('div:only-child:last').css('background-color',"#ccc");

Object-Oriented JavaScript, how to achieve private properties/fields

The very basic of Object-Oriented Programming (OOP) is private fields and public methods (not considering features like polymorphism, inheritance, etc). So how to achieve this very basic of OOP in JavaScript. It turns out to be easy. Here is how to have private fields in your custom JavaScript functions/classes and using methods of your function/class to amend it.

function User() { 
  var name = ''; 
  return { 
    setName: function(newName) { 
      name = newName; 
    }, 
    getName: function() { 
      return name; 
    } 
  } 
} 
var user = User(); 
user.setName("My Name"); 
user.getName(); // My Name

The User() class we just created could be considered a bean in Java. Using this template you can have as many private fields and public methods as you want.

How jQuery's plugin/extension system works

Recently I was reading about extending jQuery's functionality and plugin system. I wrote two articles on extending jQuery functionality with your own custom functions.  To extend you write $.fn.myFunction and then your function. It was interesting what $.fn is, so I look through the jQuery code and on line 33 found:

jQuery.fn = jQuery.prototype = {

So jQuery's fn is just a synonym for its prototype. I know this is not a discovery of the century but it gives you some understanding of how jQuery's plug-in system works and its insights.

Improving jQuery code performance

Following jQuery performance related articles here is another tip to boost your jQuery code performance. You should use ID selections whenever you can. Because jQuery uses browser's native getElementById() function which is much faster.

Now back to JavaScript code performance testing. I have an unordered list with 1000 items. First test will have list items with class attributes and the second list will have id attributes set to its items.

console.time('test');  
for (i = 0; i < 500; i++) {  
    $('.'+i);  
}  
console.timeEnd('test'); 
// ~8204ms 

console.time('test');  
for (i = 0; i < 500; i++) {  
    $('#'+i);  
}  
console.timeEnd('test'); 
// ~32ms

As you can see selecting with element's #id is much faster. In our case 256 times (8204/32).