JavaScript is probably one of the second things that I learned when I started building websites, but when it came to building incredible fun and extensible applications that didn't come until I started using jQuery. However, some simple functions can get complicated to call on a page especially when you have to run a simple function multiple times to achieve the same result.

Plugins

jQuery plugins may sounds scary at first, but they are rather easy to implement. As part of this tutorial we will build a plugin that allows us to detect navigation url's and provide a noticeable way for us to identify to a user that they are on a page. My own site uses this method to let users know that they are in the blog section when they are on a blog post.

Closure

Let's start by identifying what a plugin looks like. First you need a function wrapper to encapsulate your function and allow it to run independently. This is a function wrapper that we will always want to use on every plugin in order to keep conflicts from arising with other scripts.

(function($){ ...
})(jQuery);

Extend

Now we can start to have a little fun with our new plugin. The next part is to start building out the basic pieces of a plugin. I build plugins a little differently then I have seen, but I try to learn from my mistakes so a few months from now this all might change if I learn to do something more efficiently.

So we want to first extend our plugin to identify it and allow us to call it later when we want to use it on the page. We do this by invoking $.fn.extend and then name our function. In this case I called it "navigation", but you can change this if you find something better. Within our $.fn.extend I like to define my default values. These are the values that can be overridden if we decide to change a particular value when we call the function. For now the only parameter that I want set is the class that we will need to pass for our CSS to show what link is active.

However, a prickly piece to this is that we have to declare these in order to use them in our function so we will need to set on "option" value to bind our default values to. This will help us use our options throughout and have them easily extensible later without issue of having to rewrite our code. And finally we have our return, which is where the real work of our plugin will be done.

(function($){ // Navigation URL Detect $.fn.extend({ navigation: function(options) { var defaults = { active: 'on' }; options = $.extend(defaults, options); return this.each(function() { ... }); } });
})(jQuery);

Function

Not sure if this fits into a best practice or worse practice, but I prefer to declare all my variables at the top of the function and use them as objects. You could theoretically string your variables together and declare their values for use. For this I'm passing 3 variables: $o, $obj, and $leng. $o is the options that I have set above, so "active" will get passed into this. $obj is $(this) if you are familiar with straight jQuery coding (this is more preference based because I don't like $this cluttering up code, so you could actually simply pass $this, instead of $obj). Then we have $leng which we will use exclusively for this plugin to keep the length of the href we are going to compare.

return this.each(function() { var $o, $obj, $leng; $o = options; $obj = $(this); $leng = 0; ...
});

Get to the Navigation

Now we can get to building the navigation function that will show our users what page they are on. From the example below we are first going to grab the $obj, in this case the class or ID for our navigation and find each "a" within it. This will give us the chance to match a url against the url browser path to find a match. I will set on more var "path" inside this function for sanity sake, but you can define this above with the rest if you like. This will find each href and hold it for us so that we can compare it.

We are now going to write an if statement that compares each href value that is received and validates it against two parameters. We will find first the window.location.pathname returns the path after the domain name, so for example if you are on http://www.somewhere.com/blog this will return "/blog" as the value. After that "indexOf" helps us with a basic function that returns the index of path, which is our page. In our comparison we also check the lengths of both the current page and its parent to see if we can match a section rather than the direct url. This comes in handy when you are trying to identify the blog section when you are reading a blog.

From there we can add our class to the current link and remove it from any other pages that might have it accidentally. The last piece "siblings" is more of a catch for any stray classes that might be lingering.

$($obj).find('a').each(function(){ var path = $(this).attr('href'); if(window.location.pathname.indexOf(path) != -1 && path.length > leng){ leng = path.length $(this).addClass($o.active).siblings().removeClass($o.active); }
});

There is our navigation plugin in a nutshell. It simply checks the browser url, compares it to all the links in our navigation and then identifies the link that we are currently on (or pages that might be parents to the page we are on). However, if nothing returns true then our navigation doesn't do anything, but stay deactivated.Here is the completed code.

Complete Plugin

(function($){ // Navigation URL Detect $.fn.extend({ navigation: function(options) { var defaults = { active: 'on' }; options = $.extend(defaults, options); return this.each(function() { var $o, $obj, $leng; $o = options; $obj = $(this); $leng = 0; $($obj).find('a').each(function(){ var path = $(this).attr('href'); if(window.location.pathname.indexOf(path) != -1 && path.length > leng){ leng = path.length $(this).addClass($o.active).siblings().removeClass($o.active); } }); }); } });
})(jQuery);

Activating

Wait, wait one minute, I forgot to tell you how to turn on this plugin. Plugins are nice in this way. They stand in the back of the hall until their name is called to the dance floor. To activate our plugin all we need to do is call it in a document.ready function. And here we go.

$(document).ready( function { $('nav').navigation();
});

That was it. Now our plugin will fire and search our "nav" element for any links that match the browser url. You can also change the active class that gets fired by changing the default value that we set earlier. For this piece we can call the function as usual and add one our new class. For example, let's say that we want to have the class be "current" instead of "on". So what we need to do is call our plugin, but this time append the value that we want to change. For this to work you have to invoke the option and put add your new value. In this case we will change it current.

$(document).ready( function { $('nav').navigation({ 'active' : 'current' });
});