3 Quick Steps for a Painless Upgrade to jQuery 1.3

Since the release of jQuery 1.3 a month and a half ago, I've been keeping my eye on any troubles that people have had with their upgrades. Fortunately, most people have had no problems at all. For those who have, the issues have almost always been in one of three areas. Identifying these areas and adjusting any legacy scripts ahead of time will go a long way toward ensuring a smooth transition to jQuery 1.3.x.

1. Update Attribute Selectors

By far the most common stumbling block to the 1.3 upgrade has been the attribute selector. The XPath syntax for this selector — [@attribute] — has been deprecated since version 1.1.4 in August, 2007. Still, many scripts, including some prominent plugins, continued to use the old syntax, which wasn't a problem until jQuery 1.3, at which point it was no longer supported. The correct syntax (since 1.1.4) follows the CSS standard: [attribute].

The fix is quite simple. Simply search your scripts for [@. Go through the matches one by one, and if the string is being used as an attribute selector (and not, for example, in a regular expression), replace it with [.

Removed XPath Syntax

This will break your code in jQuery 1.3+:

[js]$('a[@href^=http]'); $('[@title=foo]'); [/js]
Current CSS Syntax

Use this instead:

[js]$('a[href^=http]'); $('[title=foo]'); [/js]

2. Check Custom Selectors

If you are using custom selectors, either in your own script or within a plugin, you might run across an error if the second argument's object value is a string:

[js]jQuery.extend(jQuery.expr[':'], { hasSiblings: "jQuery(a).siblings(m[3]).length>0" });[/js]

This is another easy fix. Simply change that value to an anonymous function and add what was in the string to the return statement:

[js]jQuery.extend(jQuery.expr[':'], { hasSiblings: function(a,i,m) {return jQuery(a).siblings(m[3]).length>0;} });[/js]

So, basically, you just change "jQuery(a).siblings(m[3]).length>0" to function(a,i,m) {return jQuery(a).siblings(m[3]).length>0;}.

When someone on the jQuery Google Group was having trouble with George Adamson's excellent More Selectors plugin, all I had to do to make it compatible with jQuery 1.3 was update the attribute selectors and change custom selectors (my updated script is available here temporarily until George has time to update the original).

3. Note Visible and Hidden Elements

This change didn't occur until jQuery 1.3.2, but if you are upgrading to the latest and greatest jQuery version, you'll want to be sure your scripts aren't relying on a quirk in how jQuery was determining the visibility of elements. Prior to 1.3.2, if you had an element with display:block inside a containing element with display: none, the inner element would still be reported as visible.

[html] [/html]

Before version 1.3.2, $('#inner'1).is(':visible') would return true and $('#inner1:hidden') would match 0 elements. In order to find out if an element were truly hidden, meaning you couldn't see it, you'd have to check all of its ancestors to see if they were hidden as well. Remy Sharp put together a little custom selector to check if elements were *really* visible.

With 1.3.2, $('#inner').is(':visible) returns false and $('#inner:hidden') match 1 element.

Another Visible Wrinkle

There is one more change in how visibility is detected in 1.3.2: elements with visibility: hidden are now considered visible, whereas before they were considered hidden.

[html]
[/html]

Given the above div structure, jQuery 1.3.2 considers #inner2 visible while prior versions considered it hidden.

Here is a quick demo, with two iFrames showing the differences in determining visibility:

I'm not sure how I feel about the new behavior with visibility:hidden, but I think the change was important for performance reasons.

A Few Others

There are a few other issues that may affect a small minority of users, but the three above represent the lion's share of reported problems that I've seen on the Google Groups. For more information about changes, see the jQuery 1.3 Release Notes