More information about the Underscore mailing list

[_] onBlur/OnChange/witsEnd

Pete Fairhurst pete.fairhurst at gmail.com
Thu Oct 4 16:11:32 BST 2007

Hello [_] massive,

Please help--I'm losing the will to live.

I'm trying to build an accessible form-based tag cloud, wherein users click
on any number of tags to enable or disable them from a search filter.  When
clicked, a tag's class should change so that it appears to hilight or reset
as appropriate.

My HTML currently looks like this:

<form action="/" method="get" id="eventFilter">
    <ul class="tagCloud">
        <li class="weight0"><label class="tag"><input type="checkbox"
name="tagAlpha" class="checkbox"/>alpha</label></li>
        <li class="weight2"><label class="tag"><input type="checkbox"
name="tagBravo" class="checkbox"/>bravo</label></li>
        <li class="weight1"><label class="tag"><input type="checkbox"
name="tagCharlie" class="checkbox"/>charlie</label></li>
        <li class="weight0"><label class="tag"><input type="checkbox"
name="tagDelta" class="checkbox"/>delta</label></li>
        <li class="weight3"><label class="tag"><input type="checkbox"
name="tagEcho" class="checkbox"/>echo</label></li>
        <li class="weight4"><label class="tag"><input type="checkbox"
name="tagFoxtrot" class="checkbox" checked="checked"/>foxtrot</label></li>
</form>

The pertinent CSS looks like this:

.tagCloud label.hilite {
    background: #ff0;
}

.tagCloud label.tag input.checkbox {
    display: none;
}

And the JavaScript looks like this:

function tagFilter(id) { //called once the page has finished loading
    //  Find filter object
    var form = document.getElementById(id);
    //  Find all checkboxes
    var tagInputs = getInputsByType(form, 'checkbox');
    //  Loop over tag checkboxes
    for(var i = 0; i < tagInputs.length; i++) {
        //  Bind 'onchange' function to encapsulating LABEL element
        tagInputs[i].onblur = function() {
            updateTag(this.parentNode);
        }
        //  Change style of encapsulating LABEL element if already selected
        if( getAttr(tagInputs[i], 'checked') || getAttr(tagInputs[i],
'checked') == 'checked' ) {
            updateTag(tagInputs[i].parentNode);
        }
    }
}

function updateTag(tag) {
    var checkboxes = getInputsByType(tag, 'checkbox');
    var checkbox = checkboxes[0];
    if( checkbox.value == 'on' && !HasClassName(tag, 'hilite') ) {
        AddClassName(tag, 'hilite');
    }
    else {
        RemoveClassName(tag, 'hilite');
    }
}

This works in Firefox, but not in IE.  IE doesn't execute the 'onchange'
binding until after the 'onblur' event for the label in question fires.
More worryingly, IE completely fails to register the label being clicked
when the inner checkbox for each is hidden using CSS.

I really am close to taking a fresh piece of A4 to either wrist at the
moment, so any and all musings greatly appreciated right now.  :'(

- Pete

_____________________________________________________________________

"Print is dead."

- Dr. Egon Spengler, Ghost Busters (1984)
_____________________________________________________________________