jQuery toggle functions don’t work in 1.3.2

I was messing with a prototype of a page which linked to jquery 1.3.2. I used slideToggle, tested is(“:hidden”) and various other methods and I couldn’t get it to work. It was like the div I was trying to hide/show was always visible and the toggle just showed the open animation.

Firstly a simple working example:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml">
<head>
    <script type="text/javascript" src="jquery-1.3.2.js"></script>
</head>
<body>
    <script type="text/javascript">
        $(document).ready(function() {
            $(".container > a").click(function() {
                $(".toToggle").slideToggle();
            });
        });
    </script>
    <div class="container">
        <a href="javascript:void(0);">Toggle</a>
        <div class="toToggle">
            <p>Contents to slide in and out!</p>
        </div>
    </div>
</body>

Now assume that I want to have multiple items in the div with the toToggle class and I want to float all of them in some way or another. In the below example we only have one <p> element that will be floated left, like this:

<div class="container">
    <a href="javascript:void(0);">Toggle</a>
    <div class="toToggle">
        <p style="float: left;">Contents to slide in and out!</p>
    </div>
</div>

Now you should be seeing the same problem that I’ve had. When you click the anchor tag you will see the toToggle div’s contents going from an invisible to open state upon every click.

This doesn’t happen in jquery 1.3.1. The issue was caused by a change with how an element was considered to be hidden or visible. The details about the changes were given in the release notes here.

The issue is that the jQuery that checks whether an element is hidden checks whether offsetHeight or offsetWidth is equal to zero (0) and if so the element is considered hidden, whereas in the previous 1.3.1 release of jQuery the test was done against the “visibility” and “display” css declarations.

This becomes an issue if you have floated elements within the div in our example as the offsetHeight and offsetWidth will both be zero (0). (See http://css-tricks.com/all-about-floats/ – under “The Great Collapse”)

John Resig mentioned here that we can simply add “overflow: auto” to the div’ with the “toToggle” class and it will resolve the issues… so our code would be:

<div class="container">
    <a href="javascript:void(0);">Toggle</a>
    <div class="toToggle" style="overflow: auto;">
        <p style="float: left;">Contents to slide in and out!</p>
    </div>
</div>

This solves the issue. (albeit with people complaining that the overflow:auto should be put in a stylesheet etc.)

jQuery changes

jQuery 1.3.1 (line 2250 and following)

Sizzle.selectors.filters.hidden = function(elem){
    return "hidden" === elem.type ||
        jQuery.css(elem, "display") === "none" ||
        jQuery.css(elem, "visibility") === "hidden";
};

Sizzle.selectors.filters.visible = function(elem){
    return "hidden" !== elem.type &&
        jQuery.css(elem, "display") !== "none" &&
        jQuery.css(elem, "visibility") !== "hidden";
};

jQuery 1.3.2 (Line 2369 and following)

Sizzle.selectors.filters.hidden = function(elem){
    return elem.offsetWidth === 0 || elem.offsetHeight === 0;
};

Sizzle.selectors.filters.visible = function(elem){
    return elem.offsetWidth > 0 || elem.offsetHeight > 0;
};

Found a discussions on whether the jQuery 1.3.2 code is correct. Ticket #4374 & Ticket #4512. And there is going to be a change again it seems… This is the latest nightly code as of 2009-11-04…

2009-11-04 Nightly of jQuery

Sizzle.selectors.filters.hidden = function(elem){
    var width = elem.offsetWidth, height = elem.offsetHeight,
        force = /^tr$/i.test( elem.nodeName ); // ticket #4512
    return ( width === 0 && height === 0 && !force ) ?
        true :
            ( width !== 0 && height !== 0 && !force ) ?
                false :
                    !!( jQuery.curCSS(elem, "display") === "none" );
};

Sizzle.selectors.filters.visible = function(elem){
	return !Sizzle.selectors.filters.hidden(elem);
};

References:

FlySpray for Bug Tracking

Another staff member at work found DocuWiki and then found out that they use FlySpray as their bug tracking software.

The demo looks interesting…