Click here to Skip to main content
Click here to Skip to main content
Go to top

A jQuery plugin for an Adaptive 960 Grid System

, 3 Oct 2011
Rate this:
Please Sign up or sign in to vote.
Article discussing the development of a jQuery plugin to be used with adaptive 960 Grid System

Introduction

I have long been a fan of the work at 960.gs, in my opinion, its simplistic approach in the layout and design of a web page will most likely interest others.

My interests in jQuery over the last couple of years have been equally as great (probably more). Mostly because I like the idea of how it simplifies JavaScript development into a reusable library so that I don't have to clutter my own development. So recently when I came across some JavaScript code at http://adapt.960.gs to make web pages adaptive to the changing sizes of web browser, naturally, I started looking into an even simpler approach.

Of course, I wanted something that could be done in the form of a jQuery plugin and that would ease my daily development.

So in this article, I will go over the details of developing a jQuery plugin, while at the same time creating something that we all can use in our daily development.

Background

Ok so for all you jQuery developers out there (both old and new), you probably know how you want a plugin to work right?

Personally, I am always amazed with those plugins where you, as the developer, using them write like one line of code and then all this really cool stuff just happens. You know the kind of stuff that would have normally taken you several dozen or even worse several hundreds of lines of code to write (not to mention the hours).

Don't get me wrong, I love the complex problems, but once they have been solved by me or someone else, then my interest level diminishes. There are only so many ways to improve the design of a wheel in my opinion.

I want something like the following to fit neatly into a script block on a web page:

// variable to hold instance of my plugin
var plugin;

$(function() {
    plugin = new $.jQueryAdaptive960(window);

    // other code to be run on page load
 });

Basics of a jQuery Plugin

Let's go over the quick basics of a jQuery plugin by showing a simple framework for the layout of one.

;(function($) {
    $.jQueryAdaptive960 = function(element, options) {
	var defaultOptions = {
	}

	// save the element
         	var pluginElement = el;

	var jQuery960 = this;

	var init = function() {
	    if(options) {
		jQuery960.settings = 
			$.extend(defaultOptions, options);
	    }
	    else {
		jQuery960.settings = defaultOptions;
	    }

	    // other init stuff for you plugin goes here
	}

	// your own plugin development stuff goes here

	// always keep this at the end
	init();
    }
}) (jQuery); 

Looks simple right? Let me go over things with a bit more detail.

The first and last line of the plugin are how we make this control become a part of jQuery as well ensuring that we still have access to jQuery itself. We have this awesome framework so we want to make sure that in our plugin development we can still use it.

The entry into our plugin starts with the $.jQueryAdaptive960 = function(element, options) where the plugin object is created as well as the receiving objects it will work with.

The first parameter to our jQuery plugin, element, and in about 99% of the cases where you develop a jQuery plugin, you find the control or page element. In the case of this plugin, we will be passing the window for reasons to be explained later.

The second parameter is simply any options that the page developer and user of the plugin may want to pass in. Very important that you understand the options passed into the plugin are optional because sometimes the developer will just want the thing to work. We will see later in the init function how we handle this scenario.

Now let's move on to the meatier side of the plugin.

Plugin Settings

Remember that I said it is important to understand that some developers will never want to pass any options into your plugin. Taking this into consideration, you will want to make sure that your plugin has a default set of options of which to operate with. We handle this by creating an object to contain our defaultOptions that we will be using.

I don't want to get into the details of object oriented programming with JavaScript but the following will be how we expose our public properties to the outside world:

// save the element
var pluginElement = el;

var jQuery960 = this;

For all of you object oriented purists out there (yeah you know who you are), please don't flame an argument about how JavaScript is not an object oriented language.

Whatever is assigned to jQuery960 will now become a publicly accessible property, or function to whoever uses the plugin.

Finally, we save the element passed to us in pluginElement that we can reference it in other areas of code.

Plugin Initialization

One more step, and then you get your official (well maybe not official) badge as a jQuery Plugin Magician. Since we have already included the jQuery framework, this final step is simplified even further for us.

var init = function() {
    if(options) {
	jQuery960.settings = $.extend(defaultOptions, options);
    }
    else {
	jQuery960.settings = defaultOptions;
    }

    // other init stuff for you plugin goes here
}

// your own plugin development stuff goes here

// always keep this at the end
init();

Remember I mentioned that sometimes a developer will want to just use your plugin without passing any parameters? Well in the initialization of the plugin, we will handle this scenario by checking to see if something was passed in. In the event that we did receive something, we are going to use the jQuery $.extend() function call to update our default settings.

Finally, at the very end of the plugin, we will make a call to the init() function which will make sure that everything gets initialized. As a note of personal importance, I like to have the init() be the last line in a plugin, it ensures that everything has been loaded and is fully accessible to the rest of the plugin.

Using the Code

So now that the basics of the plugin are taken care of, let's put together a working example of how to use it.

By now I am assuming you have had a chance to review http://adapt.960.gs because the goal is to fashion that into a jQuery plugin. Remember the goal is to give the users of our plugin something simple that takes care of everything for them. I am thinking that something like the following will work:

// variable to hold instance of my plugin
var plugin;

$(function() {
    plugin = new $.jQueryAdaptive960(window);

    // other code to be run on page load
 });

Default Settings

So in the direction of keeping things simple, I thought it best to bundle all of the required CSS files with the plugin. At the same time, I want to make sure to cater as much as possible to those looking to take things a step further.

The following should be enough to support both developers and their individual use:

var defaultOptions = {
    ranges: ['0px    to 760px  = mobile.css',
    '760px  to 980px  = 720.css',
    '980px  to 1280px = 960.css',
    '1280px to 1600px = 1200.css',
    '1600px to 1920px = 1560.css',
    '1940px to 2540px = 1920.css',
    '2540px           = 2520.css'],
    path: 'jquery960/css/',
    onResize: function () { },
    onRotate: function () { }
}

To make this plugin extensible, I make both the ranges and the path for the CSS information an option that can be replaced by developers. Then I added two callback functions so that the developer can be notified when the browser is being resized as well as rotated.

If you have read through the code at http://adapt.960.gs, you will notice they had a dynamic variable to turn on/off the dynamic abilities to update the page. At first, I had that option configurable but then I thought if they don't want it be dynamic then they most likely won't have a need for the plugin.

Plugin Initialization

With the settings all in place, now let's move on to the initialization of the plugin. Our initialization steps should be fairly simple. Most of what we are going to be handling in this step is the subscription to events to notify the plugin of when the browsers size has changed or it has been tilted.

var init = function () {
    if (options) {
        jQuery960.settings = $.extend(defaultOptions, options);
    }
    else {
        jQuery960.settings = options;
    }

    if (pluginElement.addEventListener) {
        pluginElement.addEventListener('resize', reactiveDisplay, false);

        if (pluginElement.onorientationchange) {
            pluginElement.addEventListener
		('orientationchange', rotateDisplay, false);
        }

        setTimeout(checkDisplayOrientation, 1000);
    }
    else if (pluginElement.attachEvent) {
        // old ie support and there is no support for orientation
        pluginElement.attachEvent('onresize', reactiveDisplay);
    }
    else {
        // definitely no orientation support
        pluginElement.onresize = reactiveDisplay;
    }

    adaptDisplay();
}

As said before, basically everything being done is to subscribe events. This should give the plugin the ability to work across most (hopefully all) of the browsers in operation. The important part to take note on is the last line where a call to adaptDisplay() is made.

Active Screen Adaptations

I don't intend to go over every line of code in the function adaptDisplay(), the details of what is happening lie in the while loop as it iterates through defaultOptions.ranges searching for a range that fits with the browser's current dimensions.

var adaptDisplay = function () {
    ....

    // get the width of the browser
    var width = pluginElement.innerWidth || 
		pluginElement.document.documentElement.clientWidth || 
		pluginElement.document.body.clientWidth || 0;

    // loop through each of the items inside of defaultOptions.ranges
    while (index--) {
        item = defaultOptions.ranges[index].split('=');

        range = item[0];
        cssFile = item[1] ? item[1].replace(/\s/g, '') : index;

        // check to see if a range has been specified
        is_range = range.match('to');

        // get the min and max values for the range
        val_1 = is_range ? parseInt(range.split('to')[0], 10) : parseInt(range, 10);
        val_2 = is_range ? parseInt(range.split('to')[1], 10) : undefined;

        // check to see if the width of the browser falls 
        // within the range of the current range setting
        if ((!val_2 && index === (rangeLen - 1) && width > val_1) || 
				(width > val_1 && width <= val_2)) {
            url = defaultOptions.path + cssFile;
            break;
        }
        else {
            url = '';
        }
    }

    ....
}

In the case of our default settings for the plugin, a valid range containing a CSS file will always be found to match with the browsers current size. You will notice as you resize the browser this code gets exercised and if you view the source of the page (not the original source), you will see the link for the CSS file being changed.

The page adapting itself to the new size is the inner working of the browser in conjunction with CSS file that it was informed to render against.

Viewing Page Source

Important Note

When viewing the page source, make sure that you are viewing the active document. If you don't see a line in the header that looks similar to the following...

<link href="jquery960/css/###.css" rel="stylesheet" />

...then you most likely are not viewing the page's active source.

Notification Events

The important thing to take note of in all of the notification handlers is how they handle notification back to the developer using the plugin. Remember the original idea was to allow a developer to use the plugin and only have to supply the window that it will be working with. This scenario is handled by giving the callback functions a default function handler.

var defaultOptions = {
    ....
    onResize: function () { },
    onRotate: function () { }
}

Should the developer want to extend their use of the plugin and be notified of these events, they only have to change their call in how they use the plugin.

The following is an example of how to override the control and be notified of when the browser is resized or tilted:

$(function () {
    var plugin = new $.jQueryAdaptive960(window, { onResize: function () { }, 
			onRotate: function () { } })
});

Points of Interest

Check out http://jquery.com/ for more information on this amazing JavaScript framework.

For more information on the 960 Grid System, check out http://960.gs/.

History

  • 3rd October, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

Share

About the Author

Dennis E White
Software Developer
United States United States
I am software developer with over 20 years of professional experience. I have been employed as a software developer since the early 90′s back when Microsoft’s Windows 3.1x was gaining popularity and IBM’s OS/2 was the predominant leader in 32-bit PC based Operating Systems.
 
Prior to choosing this as my profession I had studied architecture and then later Electrical and Mechanical engineering in college. As a young kid growing up I always played with computers, my first computer was a TRS-80 that I would spend countless hours writing programs for, I never really thought of programming as a profession. The story goes that in my final year of college I took a C/C++ programming class and had so much fun working on the various projects that my professor told me something that changed everything.
 
“You know they pay people to do stuff like this for a living?” – Professor Bolman
 
Check out my blog here.
 
My current and ever evolving projects:
 
jqAlert javascript alerts done right for those using jQueryUI.
DooScrib Doodle and scribble pad written in javascript for use with HTML5 Canvas.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
QuestionHow can i get return range on onResize: function () ? PinmemberVõ Minh Mẫn20-Aug-12 16:34 
AnswerRe: How can i get return range on onResize: function () ? PinmemberDennis E White21-Aug-12 5:54 
I would change a few things...
 
var reactiveDisplay = function () {
    clearTimeout(timer);
    defaultOptions.onResize();
    timer = setTimeout(adaptDisplay, 50);
}
 
remove the following line:
defaultOptions.onResize();
 
in the adaptDisplay() function search to the bottom where the css for the page is actually being modified:
 
if (urlOld) {
    css.href = url;
    urlOld = url;
}
else {
    css.href = url;
    urlOld = url;
    (pluginElement.document.head || pluginElement.document.getElementsByTagName('head')              [0]).appendChild(css);
 
    // add code change here
    defaultOptions.onResize(index, width);
}
 
the only downside of course is that your resize will only be called in those limited cases. in other words not all resizes will get a callback. that may or may not suffice for you.
 
you should also change the defaultOptions at the very top to properly deal with the change in the onResize callback. thought you can get away with not doing it if you really wanted.
 
var defaultOptions = {
    ranges: ['0px    to 760px  = mobile.css',
             '760px  to 980px  = 720.css',
             '980px  to 1280px = 960.css',
             '1280px to 1600px = 1200.css',
             '1600px to 1920px = 1560.css',
             '1940px to 2540px = 1920.css',
             '2540px           = 2520.css'],
    path: 'jquery960/css/',
    onResize: function (index, width) { },
    onRotate: function () { }
}
 
I haven't tested all of the above but I don't see any reason why it wouldn't work. If you would please post an update I would really appreciate.
 
Happy to hear that you are getting a use from this.
as if the facebook, twitter and message boards weren't enough - blogged

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140905.1 | Last Updated 3 Oct 2011
Article Copyright 2011 by Dennis E White
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid