-
A Date Range jQuery Plugin for Generating Date Options
View the Demo | Download the Zip
Creating the specialized Request for Proposal form during the development process for Durham Convention Center's (DCC) new website was no easy task, but it was fun. This form provided some unique user-interaction opportunities. We need to capture a significant amount of date&time-centric information: event dates, catering needs, overnight rooms, etc.
Furthermore, after reviewing their previous form, I realized I needed to generate input options on-the-fly based on a submitted date range. Using jQuery and the jQuery User Interface's datepicker widget here is a simple javascript Date Range plugin based on my work from the DCC RFP form.
Overview
The idea for the plugin is to have a user enter a date range, then generate other input options based on that date range. Taking an example from the DCC site, users would input catering requests for their event, and we would then populat a dropdown menu of event dates for the users to pick from.
Requirements
- jQuery 1.4.0 or greater
- jQuery User Interface 1.7.2 or greater
- Any jQuery UI Theme
The Markup
The html for this plugin is simple. You will need two input fields and a container for output. Here I'll use the '#output' <div> for the container.
<form id="date-picker"> <fieldset> <legend>Input</legend> <p><label>Start Date:</label> <input id="start_date"type="text" value="" /></p> <p><label>End Date:</label> <input id="end_date" type="text" value="" /></p> </fieldset> <fieldset> <legend>Output</legend> <div id="output"> </div> </fieldset> </form>
The Javascript
The javascript is straight forward as well. It needs to know where the date information ('startDate' and 'endDate' options) is coming from and then what kind of output ('output' option) is desired. At the moment, There are three types of output: Dropdown List, Checkbox List and Radio Button List.
$('#output').nmcDateRanger({ startDate: '#start_date', endDate: '#end_date', output: 'radio' });Conclusion
There you have it! Using some very simple javascript markup, I prevented users from entering duplicate information. While I had some specific uses for this code – including a room-reservation table, I'm interested in hearing about other output types and potential applications for the plugin.
-
A jQuery Flickr Feed Plugin
View the Demo | Download the Zip
We often work with clients that maintain accounts with Twitter, Flickr, Youtube and other services in addition to their website. Often they will want to pull in data from one of their accounts to their website. With Flickr, this is pretty easy because they make a simple API available. Having worked with it a few times, we decided to make it even easier to pull photos from a public feed.

There are a few examples of this in use on the demo page. All of the photos on this page have been used with the generous permission of John Roberts (@jroberts13).
Plugin Overview
This plugin works by pulling a JSON feed from Flickr and applying the data it gets back to a template. For example, we can generate this list of pictures:
<ul> <li><img alt="Photo Title" src="http://farm4.static.flickr.com..." /></li> <li><img alt="Second Photo Title" src="http://farm4.static.flickr.com..." /></li> </ul>
From the following jQuery:
$('ul').jflickrfeed({ limit: 2, qstrings: { id: '44802888@N04' }, itemTemplate: '<li><img alt="{{title}}" src="{{image_s}}" /></li>' });The plugin gets the feed from Flickr using AJAX and applies each image it gets back to the provided template.
The Plugin Options
There are a number of options available on the plugin, these are the defaults:
flickrbase: 'http://api.flickr.com/services/feeds/', feedapi: 'photos_public.gne', limit: 20, qstrings: { lang: 'en-us', format: 'json', jsoncallback: '?' }, cleanDescription: true, useTemplate: true, itemTemplate: '', itemCallback: function(){}Here is a description of each one:
- flickrbase: This is unlikely to be needed. It is used to set up the url the jQuery AJAX call will need to be made to.
- feedapi: There are a number of feeds that flickr makes available. The default is the public feed. Here is the list of all that are available: http://www.flickr.com/services/feeds/. This has only been tested on feeds that return photos. So, for example, don't expect good results using this plugin on the Forum discussion feeds.
- limit: Set how many items you want to loop through. Flickr seems to limit its feeds to 20, so that is the default.
- qstrings: This is the most important setting. This is used to request the correct feed. In my examples I use this to set the user id. These are automatically added to the request url. Depending on which feed you use (http://www.flickr.com/services/feeds/) there are different sets of query parameters available: http://www.flickr.com/services/feeds/.
- cleanDescription: Flickr puts all kinds of junk in the description it returns. By default this plugin is set to remove everything but the plain photo description.
- useTemplate: Set this to false if you don't want to use the plugins templating system.
- itemTemplate: The template rules are described below.
- itemCallback: You can add a callback on each item. The scope is set to the container and the item object is made available.
Typically, the only things that will need to be set are limit, qstrings.id and itemTemplate.
Using the Templates
In order to make it really easy to use any kind of markup needed with this plugin, a simple templating system has been build in. Here is an example of a template:
<li> <a href="{{image_b}}"><img src="{{image_s}}" alt="{{title}}" /></a> </li>You can see that this is just basic html with a few special tags mixed in. All of the tags are surrouned by double curly braces. The plugin works by putting in the correct information for each tag and each item into the template.
The tags that are available depend on what flickr returns for each item. For the Public Photos API these are: title, link, date_taken, description, published, author, author_id, tags, and image. For the image property, the plugin uses the Flickr URL scheme to make several sizes available. You can read about this at http://www.flickr.com/services/api/misc.urls.html. The image tags available are: image_s, image_t, image_m, image, image_b.
The Callback Parameter and Integration
The plugin's second parameter is a callback. This has the scope of the containing element and has the entire data response available. This is a great feature if you want to integrate this plugin with others. Let's say you want to integrate it with colorbox. If you call $('selector').colorbox() and then this plugin it won't work. This is becuase the plugin is adding elements to the page after the colorbox call. This is even true if you call colorbox after this plugin. Since this uses ajax, your images won't be added to the page until well after most of your javascript has run. (In computer time).
Instead, the trick is to use the callback function. This allows you to pass in code that you want to run after the images have loaded. So for example, you can do this:
$('#cbox').jflickrfeed({ limit: 14, qstrings: { id: '37304598@N02' }, itemTemplate: '...example...' }, function(data) { $('#cbox a').colorbox(); });Now the colorbox call won't be made on the photos until they are loaded.
Demo and Download
You can see a demo of this plugin on the demo page. Additionally you can download a zip of this plugin and the example.
As always, if you have any questions or comments, leave them below. Enjoy!
-
Free Regular Expression Tool for Writing and Testing RegExps
You know the green-on-black code flying all over the computer screens in The Matrix? Regular Expressions don't look too different. They can be really gnarly and debugging them is a pain. This is why we created a free Regular Expression tool to help learn, author, and test RegExps.
Regular Expressions are a powerful way of programmatically searching for and replacing text. They're used in a wide variety of ways. Some examples include validating inputs to ensure a user has provided a valid phone number and email address, finding all links to external websites on a web page, extracting content from one website to another, etc.
I will be using the HiFi RegExp Tool in an upcoming blog post series on "Getting Comfortable with Regular Expressions". You should subscribe to our development blog to receive updates on this series as they come.
-
GetHiFi.com is all Rainbows and Sunshine
We recently launched a teaser-site for our upcoming CMS, HiFi. It's still a bit premature to be talking about the details of HiFi in this space (sorry!), so instead I want to explain how we implemented the nifty color-changing header.
Joel deserves most of the credit here, since he came up with the concept and did most of the coding. I just tweaked things for a smoother result.
The secret to the ever-changing color scheme is an 8000-pixel wide image containing a continuous color gradient. This image is tiled vertically across the header section of the website and overlaid with several other semi-transparent PNGs (IE6? We don't need no stinking IE6) containing the logo, hightlight around the logo, and the dark edges along the top and bottom.

We are using JavaScript to slowly move the gradient from right to left, exposing a contiuously changing portion of the color spectrum. The script itself is very simple, but it relies on jQuery and the jQuery Background-Position Animation Plugin.
$(document).ready(function(){ var initialPos = (Math.floor(Math.random()*8000)+90000) + 'px 0'; $('#slider') .css({backgroundPosition: initialPos}) .animate({backgroundPosition: '(0 0)'}, 1500000, 'linear'); });We start by generating a random initial position along the gradient. Actually, we're starting at the end, and moving backwards so the colors fade from right to left. Once we set the starting position, all we need to do is setup a very slow animation of the background position. The animation takes 1500 seconds—25 minutes—and will cycle through the full rainbow twelve times. Since background-images repeat by default, the gradient will wrap around whenever it reaches the end.
That's all there is to it! Be sure to sign up on GetHiFi.com to receive a notification when we're ready to launch, and follow our blog for more behind-the-scenes information in the mean time.
-
Our Favorite Development Tools and Resources
jQuery Guides
These are posts we have written that give information and advice on general approaches to take when working with jQuery.
Building a jQuery Calendar for The Salvation ArmyThis post covers a project we did with a design partner -- building a nice looking calendar that showed the upcoming events for the Wake County Salvation Army. The events are categorized and filterable. This has the HTML/CSS/jQuery requred to build the calendar.
Why you should write mini-plugins in your projects
Create a jQuery calendar with AJAX, PHP, and a remote data source
Highlighting Raleigh with a jQuery microsite
jQuery Plugins
Whenever we do a project that requires a cool jQuery effect -- we are sure to write a plugin for it. Here is a list of the plugins we have released and you can use on your site today!
A Plugin for a Well-Designed jQuery MapThis post has been one of our most popular. We build this map with a design partner to highlight Marine Science locations across North Carolina using a highly stylized map. We have since developed this into a reusable jquery map plugin.
jQuery Portfolio Plugin that is Interactive and FilterableWe have clients that fall into a number of different categories so we wanted to build a cool portfolio that reflected that. We categorized our clients and then built a slick jquery plugin that allowed them to be filtered on the fly. This is a great resource for designers to showcase their work.
A jQuery Plugin for Easy Image Captions
CSS Sprites2 Refactored: Building an Unobtrusive jQuery Plugin
A Plugin for Expandable Code Areas
Select Multiple Checkboxes Easily
Add a Konami Code Easter Egg to your Site
CSS/HTML Techniques
Websites like Wine: CSS Techniques to make a site Better With AgeThere are CSS3 techniques you can use today that will degrade nice in older browsers. If you put them into place, your site will look better and better as more visitors begin using modern browsers. This post is a summary of the best techniques.
Lazy Development: Using Templates to Save Time
Nicer Navigation with CSS Transitions
HTML 5: Should we be excited yet?
Move your Script Tags to Quickly Improve Site Performance
Server-Side Development
How to use Bing's Powerful Search APIsBing!'s search API can provide search results programmatically as XML or JSON. Search results are fetched from various sources, including the Web, Images, News, Encarta Online, Phonebook, RelatedSearch, and Advertisements. This is a powerful resource that Google doesn't make available.
Dynamic Image Resizing with a Smarty Plugin
Unacceptable Browser HTTP Accept Headers
Launch of Recess: a Restful PHP Framework
Create a jQuery calendar with AJAX, PHP, and a remote data source
Software Engineering
Virtualization and the Throw-away ComputerA virtual machine is, as the name implies, a full-blown emulated computer that runs "sandboxed" on your desktop. Virtual machines allow Mac users to enjoy Windows from within OSX, they allow Linux to be run on Windows, and generally allow you to run virtual computers with whatever operating system you please.
-
Create a jQuery calendar with AJAX, PHP, and a remote data source

This tutorial demonstrates how to create a jQuery calendar with PHP and Javascript using a remote data source. This is an extension of my previous article about the jQuery calendar I developed for the Salvation Army of Wake County website.
The final calendar in this tutorial contains a hyperlink for each day of the month. When a hyperlink is clicked, a list of events for that day is requested from a remote script, cached client-side, and displayed on the page.
Tutorial Requirements
You should be comfortable with HTML, jQuery, and PHP. However, I explain the code step-by-step to show how all of the pieces fit together. In this tutorial I use PHP and a SQLite database; however, you may use any database for which there is a PHP PDO database driver.
Tutorial Overview
There are several pieces that work together in this tutorial.
-
/frontend.php
This is the epicenter of the tutorial. You will view this file in a web browser. This file provides the calendar's HTML markup, includes the jQuery calendar script, and displays the calendar and its events.
-
/backend.php
This connects
frontend.phpand the database. This PHP script is called remotely fromfrontend.phpand accepts a GET parameter called "timestamp". This script queries the database for all events that occur on the same day as the timestamp parameter. The events returned from the database are output in an HTML unordered list. -
/scripts/calendar.js
This Javascript file is included into
frontend.phpand uses jQuery to attachonclickevent handlers to each hyperlink in the calendar table. Each event handler will send an HTTP request tobackend.phpalong with a unique "timestamp" GET parameter. The HTTP response from each HTTP request is cached client-side to avoid duplicate HTTP requests. This script also inserts the HTML returned frombackend.phpinto the document object model offrontend.php. -
/includes/calendar.php
This PHP script contains a function written by David Walsh that creates the calendar's initial HTML markup. I made several edits to David's original function for this tutorial. You can read more about my edits in this file's header. This file is included into and called from
frontend.php. -
/db/calendar.db
This is the SQLite database file that contains a tuple for each calendar event. This file is referenced from
backend.phpwith a PDO database driver.
Step 1: Setup the database
First, create and prepare the database using the schema shown below. You need to create the database and load it with the sample data before moving on with this tutorial. If you use SQLite, create a database file called
calendar.dbin the "db" directory within the project directory. If you use the ZIP download for this project, the SQLite database has already been created for you.CREATE TABLE events ( id INTEGER PRIMARY KEY, title TEXT, slug TEXT, time INTEGER ); INSERT INTO events (title,slug,time) VALUES ('Soccer Game','soccer-game',1250256000); INSERT INTO events (title,slug,time) VALUES ('Basketball Game','basketball-game',1250361000); INSERT INTO events (title,slug,time) VALUES ('Hockey Game','hockey-game',1250367840); INSERT INTO events (title,slug,time) VALUES ('Lacrosse Game','lacrosse-game',1250438700); INSERT INTO events (title,slug,time) VALUES ('Ping Pong Game','ping-pong-game',1250463600);`id` is an auto-incrementing integer primary key
`slug` is a URL-friendly text representation of the event title
`time` is an integer UNIX timestampNext, I establish a PHP PDO database connection in the
backend.phpfile. Openbackend.phpin a plain-text editor and edit line 10 to establish a connection to the database. If you use the ZIP download for this project, the database connection has already been created for you. Visit the PHP PDO website to learn more about creating PDO database connections.$db = new PDO('sqlite:db/calendar.db');Step 2: Create the calendar markup
Next, I create the calendar's HTML markup with PHP. I see no point in re-inventing the wheel, so I use a great PHP calendar generation script by David Walsh. I make several changes to David's original function. You can read about my changes in the header of
/includes/calendar.php.The calendar is displayed in
frontend.php. First, I include the calendar function intofrontend.phpon line 1.<?php include('includes/calendar.php'); ?>Next, I call the
draw_calendar()method infrontend.phpon line 16. This outputs the entire calendar HTML markup.<h1>August 2009</h1> <?php echo draw_calendar(8,2009); ?> <div id="calendar-events"></div>
Step 3: Setup the backend PHP script
The
backend.phpscript connectsfrontend.phpto the database. Thebackend.phpscript receives an XMLHttpRequest fromfrontend.phpthat looks like this:backend.php?timestamp=1249966800Next, the
backend.phpscript asks the database for all events that occur on the same day as the timestamp. Let's walk through the code step by step.$db = new PDO('sqlite:db/calendar.db');First, I establish a PDO connection to the SQLite database. If you do not use the database provided in the ZIP download for this project, edit line 10 to establish a PDO connection to your own database.
//Set date from GET timestamp parameter if( !isset($_GET['timestamp']) ) die('You must provide a timestamp'); else $date = getdate($_GET['timestamp']);Next, I verify that a timestamp is specified. If a timestamp is not specified, I return an error message to
frontend.php. Else, I extract an array of date and time information based on the provided timestamp.//Define start and end timestamps for the requested day $time_start = mktime(0,0,0,$date['mon'],$date['mday'],$date['year']); $time_end = mktime(23,59,59,$date['mon'],$date['mday'],$date['year']);
Using the timestamp provided in the previous step, I extrapolate two additional timestamps: one for the beginning of the same day and one for the end of the same day.
//Fetch events from database as associative array $stmt = $db->prepare('SELECT id, title, slug, time FROM events WHERE time BETWEEN ? AND ? ORDER BY time ASC'); $stmt->bindParam(1,$time_start,PDO::PARAM_INT); $stmt->bindParam(2,$time_end,PDO::PARAM_INT); $stmt->execute(); $events = $stmt->fetchAll(PDO::FETCH_ASSOC);Next, I create a PDO statement and execute a SQL query against the database. This SQL query returns all events that start on the same day as the specified timestamp. Notice how I use the two extrapolated timestamps as boundaries for the
BETWEENclause. The returned events are collected into an associative array referenced by the$eventsvariable.//Send output if( !count($events) ) exit('<p>No events were found</p>'); $output = '<ul>'; foreach( $events as $event ) $output .= '<li>'.strftime("%l:%M %p",$event['time']).' - '.$event['title'].'</li>'; $output .= '</ul>'; exit($output);Finally, I output an HTML unordered list containing all of the events returned by the SQL query.
Step 4: Add XMLHttpRequest behavior with jQuery
In this last step of the tutorial, I add behavior to
frontend.phpwith jQuery. The Javascript attachesonclickevent handlers to each hyperlink in the calendar table. When a hyperlink is clicked, an XMLHttpRequest is sent tobackend.phpwith a unique timestamp parameter. When a response is received frombackend.php, the HTML returned bybackend.phpis inserted into the document object model (DOM) to reveal the events for the clicked day.You must provide the absolute or relative path to the
backend.phpon line 4 of /scripts/calendar.js. This path will be different than the path shown below.jQuery(document).ready(function($){ //CHANGE ME!!! Define the relative or absolute path to your backend script var remoteUrl = '/~joshlockhart/calendar/backend.php'; //Initialize the HTTP cache var remoteCache = new Array(); //For each link in the calendar... $('table.calendar a').each(function(i,item){ //Unique ID for the link var linkId = item.id; //Unique URL for the link var linkUrl = remoteUrl+'?timestamp='+linkId; //Attach onclick event handler $(this).click(function(){ var calendarEvents = $('#calendar-events'); calendarEvents.slideUp('fast',function(){ if( remoteCache[linkId] != undefined ) { calendarEvents.html(remoteCache[linkId]); calendarEvents.slideDown('fast'); } else { calendarEvents.load(linkUrl,function(){ remoteCache[linkId] = calendarEvents.html(); calendarEvents.slideDown('fast'); }); } }); return false; }); }); });The jQuery script caches all responses received from
backend.php. If a calendar link is clicked more than once, the list of events for the given day is retrieved from cache if available instead of sending a duplicate HTTP request. This saves bandwidth and significantly increases the responsiveness of the jQuery calendar.This script is saved in the external Javascript file
/scripts/calendar.js. I include this external Javascript on line 12 offrontend.php.Step 5: View the finished jQuery calendar
View
frontend.phpin a web browser and click on the 14th, 15th, or 16th. You should see a list of events appear for each day. Feel free to add more events to your database and watch them appear on the calendar. Post questions or comments using the form below. Enjoy! -
-
Suggest a jQuery Plugin and We'll Build It
Here at New Media Campaigns, we love jQuery. We use it on most of our projects in a variety of different ways and often take some things we've done and abstract them into plugins. Here is a quick list of some of the more popular things we have done recently:
- Building an Interactive Map with jQuery
- jCaption: jQuery Image Captions with easy Customization
- CSS Sprites2 as a jQuery Plugin
- Select Multiple Checkboxes with jQuery QuickCheck
Some of these are fairly trivial, but a couple are more complex, but we have received tons of feedback on all of them. For our next plugin writeup, we are asking our readers what plugin they would like to see.
If you have an idea for a jQuery plugin that you would like to see implemented (or re-implemented!), describe it in the comments.
At the end of March we will look through the submissions, pick those that we like best and are most feasible and put up a poll. The winner of the poll will be implemented and written up.
We look forward to hearing your suggestions.
-
App with a list of checkboxes? Skip repeated clicks with jQuery QuickCheck.
Applications have moved to the browser and with that come lists of checkboxes. It can be frustrating to click a list of checkboxes, so many applications like Gmail provide utilities to select items that meet certain criteria. Solutions exist as browser plugins (ie. CheckBoxMate, Check All ), but these have not become mainstream.As developers, we can mimick the behavior of these browser plugins with jQuery. QuickCheck is a proof-of-concept jQuery plugin that makes it easier to manipulate lists of checkboxes. Try a demo here. QuickCheck adds the following behavior to checkboxes:
- When you mouse-down on a checkbox, keep the mouse pressed and drag the cursor over other checkboxes.
- The other checkboxes with either become checked or unchecked depending on the state of the first checkbox.
QuickCheck makes it much easier to manipulate lists of html checkboxes. All you need to know to configure the plugin (besides how jQuery plugins work) is the following:
$('.multi').quickcheck(); // Applies QuickCheck to checkboxes with class 'multi'
$(':checkbox').quickcheck(); // Applies QuickCheck to all checkboxesThe plugin also has a couple of settings that let you change its behavior:
mode
default: If the initial checkbox is unchecked, it will check that box and check all boxes that the mouse is dragged over. If the initial checkbox is checked, it will uncheck all boxes.
"check": Regardless of the initial checkbox, the mouse will only check boxes it is dragged over.
"uncheck": The mouse will only uncheck boxes it is dragged over.
"toggle": The mouse will toggle all checkboxes it is dragged over.mouseup
Once the mouse is released, the plugin needs to know that it should stop selecting checkboxes when the mouse is over them. Set this to the selector you want this mouseup event to be attached to. The default is "html" which likely never needs to change.To use the settings do the following when applying the plugin:
$('.multi').quickcheck({mode: "check", mouseup: "html"});Drawbacks and Potential Improvements
This technique has some obvious benefits but it also has some drawbacks. Here are some quick thoughts on them. Please add your own throughts in the comments.
Drawbacks
- The functionality is not immediately obvious to those used to typical checkbox behavior.
- Unlike the browser plugin, there is not a visual box to show what region you have selected.
- The mouse must move directly over the box for it to be activated. This makes it tough to select boxes that are not aligned.
Potential Improvements
- Keyboard Shortcuts: Hold a key while dragging to switch between modes to quickly select/deselect.
- "Undo": If you drag over a checkbox a second time in the same run, return it to its original state.
Thanks for looking over the plugin. Download a zip of the demo and plugin here. Be sure to leave a comment with your thoughts.
-
CSS Sprites2 Refactored: Building an Unobtrusive jQuery Plugin
Note:
This post is in reference to the recent A List Apart article in which Dave Shea expands upon the classic CSS Sprites technique by using jQuery. His technique allows for animations between the link states while still being fully degradable for visitors that do not run javascript.
In this post I am going to revisit the markup, css and javascript in the CSS Sprites2 article to address some of the concerns I had when viewing it. I will also clean up the function and turn it into a handy jQuery plugin that allows for more control over the animation while requiring less initial configuration. To start things off, here is the end product of this technique using either Dave's method or the method described in this post:
To set the stage for my plugin writeup, it is important that I first describe how this technique works and the ways I would like to change it. Below is a quick overview of the original technique along with some minor changes I made to the markup and css. If you would like to jump straight to the plugin writeup, click here.
How CSS Sprites Works
CSS sprites were written up in A List Apart back in March of 2004. The premise behind sprites is that instead of slicing up an image into each of its states, we are able to use the background-position declaration in css to just reposition one giant image.
Background image containing all states.

There are a couple of benefits to using this technique. First, there is no reason to worry about image preloading, since all of the states are loaded at the same time. When you mouseover a button for the first time, there will be no flicker or pause before the hover state is shown.
Second, and perhaps more importantly, only one image is downloaded by the browser instead of as many as 4 for each button. Had we sliced the above image and implemented the menu without sprites, there could have been as many as 16 images used. Each of those images would have needed a separate request to the server and hurt the performance of your site. This is such a big issue that the Yahoo developers site considers minimizing http requests the #1 thing you can do to your content to improve page load times. (Performance Factors, YSlow Firefox add-on)
What Changes with CSS Sprites2
CSS Sprites2 keeps all of the advantages of the original technique, and then adds animation. Rather than relying directly on CSS styles to immediately show the different states, instead it uses javascript to animate between the different states. Should a user not have javascript, the technique degrades gracefully.
The javascript adds animation to the technique by placing an invisible
over the original link, setting its background-position to show the appropriate state, and transitioning it in and out on the appropriate mouse events.Now that the technique has been covered, I am going to go over the quick changes I made to the original article and then walk through the creation of the plugin.
Change to the markup
A quick concern I had with the implementation was how an active list item was indicated. Rather than giving the item itself a class, the parent unordered list is given an additional class.
Original Markup
If this seems hacky, it's because it is. Essentially it avoids an IE6 issue with multiple classes on a single element. There is not a good way around this problem while maintaining semantically clean markup. My solution was to avoid the issue by using ids instead of classes to identify the individual nav items. This has obvious drawbacks, but the IE6 Deathmarch has begun and I consider this my small contribution to the movement.
New Markup
Change to the CSS
Since I made a change to the markup, I also needed to make a change to the css. Below is the CSS for a single nav item using the original technique:
.nav .home a:link, .nav .home a:visited { left: 23px; width: 76px; } .nav .home a:hover, .nav .home a:focus { background: url(blue-nav.gif) no-repeat -23px -49px; } .nav .home a:active { background: url(blue-nav.gif) no-repeat -23px -98px; } .current-home .home a:link, .current-home .home a:visited { background: url(blue-nav.gif) no-repeat -23px -147px; cursor: default; } .nav-home, .nav-home-click { position: absolute; top: 0; left: 23px; width: 76px; height: 48px; background: url(blue-nav.gif) no-repeat -23px -49px; } .nav-home-click { background: url(blue-nav.gif) no-repeat -23px -98px; }Looking over this css, the purpose of most of it is obvious. It covers the LVHA states and treats the :focus state the same as the :hover state. Since the information about which state is selected is in the parent
-
- It pollutes the namespace with another function.
- All of the parameters are required, though they don't need to be.
- Passing in a selector for this purpose doesn't seem very "jQuery"
- The options for animation are unnecessarily limited
- allowClick - Allows click events to be disabled by setting this to false.
- show - A hash of animation options to be used when the hover is enabled.
- hide - A hash of animation options to be used when the hover is disabled.
- activeClass - The class the plugin should use to determine which nav items are active and therefore shouldn't have mouse events attached.
- clickClass - The class that should be added to the placeholder div when a nav item is clicked.
, you can see the .current-home selector at work. The last two handle the click states when javascript is enabled.
By pulling declarations upwards where possible and switching to ids, the following is the CSS for the same nav item with the new markup:
.spritesnav #snhome a:link, .spritesnav #snhome a:visited, .spritesnav #snhome div{ left: 23px; width: 76px; } .spritesnav #snhome a:hover, .spritesnav #snhome a:focus, .spritesnav #snhome div{ background: url(blue-nav.gif) no-repeat -23px -49px; } .spritesnav #snhome a:active, .spritesnav #snhome div.click { background: url(blue-nav.gif) no-repeat -23px -98px; } .spritesnav #snhome.active a:link, .spritesnav #snhome.active a:visited { background: url(blue-nav.gif) no-repeat -23px -147px; cursor: default; }Changes to the Javascript
The javascript code in the original article is well written and clean, but I believe it takes the wrong approach. Rather than use jQuery's defined plugin architecture, it is just a simple function call with a number of parameters:
$(document).ready(function(){ generateSprites(".spritesnav", "current-", true, 150, "slide"); });While this solution gets the job done, it has a couple of problems:
The obvious solution to these problems is to take the code that Dave wrote and turn it into a proper jQuery plugin. Once we are done with this, we will be able create the same sprites enabled menu using the following code:
$(document).ready(function(){ $('.spritesnav').sprites(); }By following jQuery's plugin authoring guidelines, I am making all of the parameters optional by supplying sensible defaults. When implementing a plugin, this is done by using the jQuery.extend() function. Additionally, I am following their animation guidelines which allows for any type of animation to be used that jQuery or its extensions support. Below is the plugin declaration and the jQuery.extend() call I use to set up defaults for all of my parameters:
jQuery.fn.sprites = function(settings) { settings = jQuery.extend({ allowClick: true, show: {opacity: 'show'}, hide: {opacity: 'hide'}, activeClass: 'active', clickClass: 'click' }, settings);The optional parameters above do the following:
With this set up I am ready to execute the logic of the plugin. I followed Dave's work pretty closely. The only place I parted was that I used chaining and traversal where I could rather than initiating a new selection. This probably makes the plugin (negligibly) faster while also making it a little bit easier to follow. I also kept everything in one function, eliminating a few more selections. Below is the rest of the code for my plugin with my comments stripped.
jQuery(this).children().each(function(){ if(!jQuery(this).hasClass(settings.active)){ jQuery(this).children('a').css({background: "none"}); jQuery(this).hover(function() { jQuery('') .prependTo(this).animate(settings.show); },function(){ jQuery(this).children('div').animate(settings.hide, function(){ jQuery(this).children('div').remove(); }); }); if(settings.allowClick){ jQuery(this).children('a').mousedown(function(){ jQuery(this).prev().addClass('click'); }).mouseup(function(){ jQuery(this).prev().removeClass('click'); }); } } });As you can see it is extremely compact and nearly everything has become an option. If you know just a little bit of jQuery, you might be wondering why the famous '$' isn't being used in the code above. When writing a plugin, it is important to be mindful of potential collisions with other libraries. For that reason it is recommended that you use 'jQuery' instead. If you really want to use the '$' or other alias in your plugin, you can wrap your plugin in an anonymous function:
(function($) { // plugin code here, use $ as much as you like })(jQuery);If you like this plugin and want to add it to your site, below is an example you check out and a zip file containing all of the files for this project.
-











Network with Us