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:
var plugin;
$(function() {
plugin = new $.jQueryAdaptive960(window);
});
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 = {
}
var pluginElement = el;
var jQuery960 = this;
var init = function() {
if(options) {
jQuery960.settings =
$.extend(defaultOptions, options);
}
else {
jQuery960.settings = defaultOptions;
}
}
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:
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;
}
}
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:
var plugin;
$(function() {
plugin = new $.jQueryAdaptive960(window);
});
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) {
pluginElement.attachEvent('onresize', reactiveDisplay);
}
else {
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 () {
....
var width = pluginElement.innerWidth ||
pluginElement.document.documentElement.clientWidth ||
pluginElement.document.body.clientWidth || 0;
while (index--) {
item = defaultOptions.ranges[index].split('=');
range = item[0];
cssFile = item[1] ? item[1].replace(/\s/g, '') : index;
is_range = range.match('to');
val_1 = is_range ? parseInt(range.split('to')[0], 10) : parseInt(range, 10);
val_2 = is_range ? parseInt(range.split('to')[1], 10) : undefined;
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