<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>The Code Project</title>
<style>
BODY, P, TD { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt }
H2,H3,H4,H5 { color: #ff9900; font-weight: bold; }
H2 { font-size: 13pt; }
H3 { font-size: 12pt; }
H4 { font-size: 10pt; color: black; }
PRE { BACKGROUND-COLOR: #FBEDBB; FONT-FAMILY: "Courier New", Courier, mono; WHITE-SPACE: pre; }
CODE { COLOR: #990000; FONT-FAMILY: "Courier New", Courier, mono; }
</style>
<link rel="stylesheet" type="text/css" href="http://www.codeproject.com/App_Themes/NetCommunity/CodeProject.css">
</head>
<body bgcolor="#FFFFFF" color=#000000>
<!------------------------------- STEP 1 --------------------------->
<!-- Fill in the details (CodeProject will reformat this section for you) -->
<pre>
Title: A jQuery plugin for an Adaptive 960 Grid System
Author: dniswhite
Email: denniswhite98@yahoo.com
Language: HTML, CSS, javascript, jQuery
Platform: Web
Technology: HTML, CSS, jQuery, javascript
Level: Intermediate
Description: Article discussing the development of a jQuery plugin to be used with adaptive 960 Grid System
Section HTML / css
SubSection Ajax
License: GPL, MIT
</pre>
<!------------------------------- STEP 2 --------------------------->
<!-- Include download and sample image information. -->
<ul class=download>
<li><a href="Article_demo.zip">Download demo project - XXX Kb </a></li>
<li><a href="Article_src.zip">Download source - XXX Kb</a></li>
</ul>
<h2>Introduction</h2>
<p>I have long been a fan of the work at <a href="http://960.gs">960.gs</a>, in my opinion, its
simplistic approach in the layout and design of a web page will most likely interest others.</p>
<p>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 <a href="http://adapt.960.gs">http://adapt.960.gs</a> to make web
pages adaptive to the changing sizes of web browser. Naturally I started looking into an even
simpler approach.</p>
<p>Of course, I wanted something that could be done in the form of a <a href="http://jquery.com/">jQuery</a>
plugin and that would ease my daily development.</p>
<p>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.</p>
<h2>Background</h2>
<p>Ok so for all you jQuery developers out there (both old and new) you probably know how you want
a plugin to work right?</p>
<p>Personally, I am always amazed with those plugins where you, as the developer, using them writes
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 hundred of lines of code
to write (not to mention the hours).</p>
<p>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.</p>
<p>I want something like the following to fit neatly into a script block on a web page:</p>
<pre lang="jscript">
// variable to hold instance of my plugin
var plugin;
$(function() {
plugin = new $.jQueryAdaptive960(window);
// other code to be run on page load
});
</pre>
<h2>Basics of a jQuery Plugin</h2>
<p>Lets go over the quick basics of a jQuery plugin by showing a simple framework for the layout
of one.</p>
<pre lang="jscript">
;(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);
</pre>
<p>Looks simple right? Let me go over things with a bit more detail.</p>
<p>The first and last line of the plugin are how we make this control become a part of jQuery as
well insuring 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.</p>
<p>The entry into our plugin starts with the <code>$.jQueryAdaptive960 = function(element, options)</code>
where the plugin object is created as well as the receiving objects it will work with.</p>
<p>The first parameter to our jQuery plugin, <code>element</code>, 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 <code>window</code> for reasons to be explained later.</p>
<p>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
<code>init</code> function how we handle this scenario.</p>
<p>Now let's move onto to the meatier side of the plugin.</p>
<h3>Plugin Settings</h3>
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 <code>defaultOptions</code> that we will be using.
<p>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:</p>
<pre lang="jscript">
// save the element
var pluginElement = el;
var jQuery960 = this;
</pre>
<p>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.</p>
<p>Whatever is assigned to <code>jQuery960</code> will now become a publicly accessible property,
or function to whoever uses the plugin.</p>
<p>Finally, we save the element passed to us in <code>pluginElement</code> that we can reference
it in other areas of code.</p>
<h3>Plugin Initialization</h3>
<p>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.</p>
<pre lang="jscript">
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();
</pre>
<p>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 <a href="http://api.jquery.com/jQuery.extend/"><code>$.extend()</code></a>
function call to update our default settings.</p>
<p>Finally, at the very end of the plugin, we will make a call to the <code>init()</code> function
which will make sure that everything gets initialized. As a note of personal importance I like to
have the <code>init()</code> be the last line in a plugin, it insures that everything has been
loaded and is fully accessible to the rest of the plugin.</p>
<h2>Using the code</h2>
<p>So now that the basics of the plugin are taken care of lets put together a working example
how to use it.</p>
<p>By now I am assuming you have had a chance to review <a href="http://adapt.960.gs">http://adapt.960.gs</a>
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:</p>
<pre lang="jscript">
// variable to hold instance of my plugin
var plugin;
$(function() {
plugin = new $.jQueryAdaptive960(window);
// other code to be run on page load
});
</pre>
<h3>Default Settings</h3>
<p>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.</p>
<p>The following should be enough to support both developers and their individual use:</p>
<pre lang="jscript">
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 () { }
}
</pre>
<p>To make this plugin extensible I make both the <code>ranges</code> and the <code>path</code> 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.</p>
<p>If you have read through the code at <a href="http://adapt.960.gs">http://adapt.960.gs</a> you will notice
they had a <code>dynamic</code> 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 wont
have a need for the plugin.</p>
<h3>Plugin Initialization</h3>
<p>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.</p>
<pre lang="jscript">
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();
}
</pre>
<p>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 <code>adaptDisplay()</code> is made.</p>
<h3>Active Screen Adaptations</h3>
<p>I don't intend to go over every line of code in the function <code>adaptDisplay()</code>, the details
of what is happening lie in the <code>while</code> loop as it iterates through
<code>defaultOptions.ranges</code> searching for a range that fits with the browsers current
dimensions.</p>
<pre lang="jscript">
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 = '';
}
}
....
}
</pre>
<p>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.</p>
<p>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.</p>
<h4>Viewing Page Source</h4>
<p>Important Note:</p>
<p>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:</p>
<pre lang="html">
</<link href="jquery960/css/###.css" rel="stylesheet" />>
</pre>
<p>Then you most likely are not viewing the pages active source.</p>
<h3>Notification Events</h3>
<p>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 <code>window</code> that it will be working with. This scenario is handled by
giving the callback functions a default function handler.</p>
<pre lang="jscript">
var defaultOptions = {
....
onResize: function () { },
onRotate: function () { }
}
</pre>
<p>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.</p>
<p>The following is an example of how to override the control and be notified of when the browser is resized or
tilted:</p>
<pre lang="jscript">
$(function () {
var plugin = new $.jQueryAdaptive960(window, { onResize: function () { }, onRotate: function () { } })
});
</pre>
<h2>Points of Interest</h2>
<p>Check out <a href="http://jquery.com/">http://jquery.com/</a> for more information on this amazing javascript framework.</p>
<p>For more information on the 960 Grid System checkout <a href="http://960.gs/">http://960.gs/</a></p>
<h2>History</h2>
</body>
</html>