Polyfill for Reversed Attribute on Lists

Lists in HTML typically appear in decimal fashion, starting from 1 and going to n. Sometimes these are instructed to appear in reversed order via the reversed boolean attribute on the ol element.

<ol reversed>
    <li>I am number two.</li>
    <li>And I am number one.</li>
</ol>

Some browsers don’t understand the reversed attribute, and thus will not reverse the list. Although you cannot reverse the entire list in some browsers with this attribute, you can manually override the value associated with each list item in most browsers via the value attribute.

<ol>
    <li value="2">I am number two.</li>
    <li value="1">And I am number one.</li>
</ol>

Using jQuery, we can quickly create a short polyfill that will give us reversed functionality in browsers where it’s not natively understood.

(function () {
    if ( $("<ol>").prop("reversed") === undefined ) {
        $("ol[reversed]").each(function () {
            var $items = $(this).find("li");
            $items.attr("value", function ( index ) {
                return $items.length - index;
            });
        });
    }
}());

The code should be fairly straight-forward, but let me explain what is going on just to be on the safe side.

We start with an IIFE (Immediately Invoked Function Expression) which runs our code instantly, as well as keeps all declared variables out of the global namespace.

Next we kick things off with a quick feature-test on a freshly-made ol. In browsers that understand the reversed property, the default value is false. In other browsers, the property is undefined.

We then grab a collection of all lists that have the reversed attribute. Next we cycle over this collection of lists, assigning the list items from each iteration to the variable $items.

We then take the $items jQuery collection and begin an implicit loop setting the value attribute of each item in the collection to collection.length - itemIndex. If there are five items in the list, and we’re on index 0 (first item), five will be returned as the value. When we enter the second iteration, and the index is 1, (5-1) will be returned, resulting in a value of 4.

Voila, we have polyfilled reversed. There are some shortcomings; this won’t work on lists created after this code runs. You could however put this logic into a function declaration and call it after the DOM has been updated asynchronously, so as to handle any new lists that might have populated the document.

One very important note when using jQuery as a means to polyfill older browsers, you will have to use jQuery 1.8.3 or below. Around the release of jQuery 1.9, a lot of antiquated code was removed that once propped up older browsers. jQuery 1.9 and forward are meant for modern browsers, and as such they will fail in carrying your polyfilled functionality back to older browsers like Internet Explorer 6, and its contemporaries.

Phenomenal Day thanks to jQuery and Windows 8

Friday, March 29th, 2013, was a phenomenal day in this developer’s life.

In late 2012 my employer, appendTo, began working with Microsoft on an extremely exciting project – preparing a version of the web’s most beloved JavaScript library, jQuery, for Windows RT and use in Windows Store applications. This was particularly exciting for me since jQuery is one of my most active tags on Stack Overflow.

Towards the end of our work in preparing this special version of jQuery, I had the great pleasure of working with Elijah Manor on material that would be presented at //build/ 2012 by one of appendTo’s founders, Mike Hostetler.

We had successfully delivered a version of jQuery that worked with the new security model in Windows Store applications. But this wasn’t the end-goal; none of us wanted to maintain a clone of jQuery that was engineered specifically for Windows Store applications.

The project was a huge success, I was on cloud 9 having gotten to work with such phenomenal developers, and fantastic partners, on such a game-changing project. But again, our work wasn’t done – we merely wet our appetites for far better results. We wanted jQuery itself to work in Windows Store applications, not some sufficiently-similar clone of jQuery.

Our focus was then turned to working more closely with jQuery core contributors, which resulted in me getting to meet even more amazing people, like the President of the jQuery Foundation, Dave Methvin. Dave is one of those old-school hackers that could keep you tuned to his every word for hours on end; such an amazing guy. With guys like him at the helm, it’s easy to see why jQuery is such a success.

Moving forward, I began testing jQuery builds within Windows Store applications. This required forking, cloning, building, authoring and modifying unit tests, and more; it was a smörgåsbord of geek indulgence. At this time jQuery core contributors were working hard on version 2.0, the highly-anticipated version of jQuery that would shed itself of legacy support like a cicada liberated from it’s shell.

The timing couldn’t have been more perfect; Dave and the others were carefully extracting massive chunks of code from jQuery’s core that existed for no other reason than to support over a decade of antiquated browsers. In parallel to their efforts, appendTo was diving into versions of jQuery from 1.8.3 to pre-builds of 2.0, addressing any and all patterns considered “unsafe” in the new non-browser environment.

In the end, it all paid off. jQuery 2.0 appears to be ready for Windows Store applications, and every web-developer looking to try their hands in the lucrative market of Native Windows 8 applications authored in JavaScript (and now jQuery) has a familiar gateway into the new stomping grounds. It’s been an exciting project, and I’m incredibly humbled to have played a role in all of it.

jquery-pagesEverything peeked for me yesterday though, when co-worker Ralph Whitbeck and I had our article Building Windows Store Applications With jQuery 2.0 published on Nettuts+. Immediately following that, I was mentioned on the Interoperability @ Microsoft blog. And soon thereafter, mentioned on none other than TechCrunch, a site with over 1,600,000 tech-loving subscribers.

I imagine this type of thing happens everyday with various different developers. You put your nose down into a project that you are personally excited to be a part of. You work countless hours researching, writing, and testing. You meet a few exciting people along the way, and then one day you lift up your eyes to realize that you just had part in something truly amazing.

The web is such an exciting place, and contributing to open-source projects is an incredibly rewarding thing. Fortunately, for myself and all of my peers, getting your hands dirty with such amazing projects is easier today than it has ever been before thanks to services like GitHub.

As for me, I’m looking forward to seeing how jQuery 2.0 and beyond are used in Windows Store applications, and perhaps be so fortunate enough to contribute further to this amazing project in the future. You can do the same.

Creating Your Own Custom jQuery Filters

Chances are you have probably used custom filters in jQuery from time to time to save on verbose selectors. For instance, if we wanted all of the buttons, selects, inputs, and textareas within a form we could do the following:

$("button, textarea, input, select", "#myForm");

You can see how that quickly piles up and gets a bit heavy. jQuery natively provides us with the :input filter which grabs all form elements:

$("#myForm :input");

While these both do the same thing, it’s far easier to call :input than it is to construct a large selector containing all of the particular form elements we can remember at the time. There is a bit of  a performance issue with things like :input though, since they have to cycle over all potential elements. That’s why it’s wise to limit our load by providing some context, in this case we’re looking only within #myForm.

While we can do a lot with what jQuery brings out-of-the-box, we’re capable of doing so much more using some of the tools it provides us with.

You’ve likely used .filter to sift through your elements before applying some effects:

$("div").filter(":visible").hide();

The filter method can take a string expression like :visible and determine which of the div elements meet its demands, and which don’t. Those that don’t will be dropped, and all remaining will have .hide called against them. This method can take a function as well:

$("div").filter(function(){
    return $(this).text() === "Foobar";
}).hide();

Here we are manually sifting through the elements based upon some examination of their properties. We return true or false, depending on whether the current element being evaluated has the text “Foobar” or not. This solution isn’t very flexible though, what if I wanted to check different things for different strings?

Fortunately jQuery exposes itself in such a way that we can extend its base filters and add our own.

Our focus from here will be on $.expr[“:”]. Within the jQuery function ($) is an object called expr. This object has objects within, one of which is called “:”. This object is where we will place our new method, and provide the necessary functionality to determine which elements pass, and which fail.

$.extend($.expr[":"], {
    exactly: function(){
        return true;
    }
});

With nothing more than the above, we can already use our filter:

$("div:exactly");

Granted, it doesn’t do anything, but it doesn’t blow up in our face either! As is the case with most callback methods, the element currently being handled is referred to as this. With that, we could already perform some logic:

$.extend($.expr[":"], {
    exactly: function(){
        return $(this).text() === "Foobar";
    }
});

Of all the div elements we’re cycling over, only those whose text content loosely equals “Foobar” will be kept, while all others are discarded. But again, who wants to hard-code “Foobar” into the definition of the filter? Wouldn’t it be better if our filter worked like :contains in that it took some parameters?

It is at this point we need to look at the arguments passed to our function. We can do so by logging the arguments object from within:

$.extend($.expr[":"], {
    exactly: function(){
        console.log( arguments );
    }
});

$("div:exactly");

In our console we find the following:

[<div>​Hello World</div>​,   0, Array[4], NodeList[3]]
[<div>​Hello, World</div>​,  1, Array[4], NodeList[3]]
[<div>​Hello, World.</div>​, 2, Array[4], NodeList[3]]

My selector evaluated three div elements. The first argument passed to my function is the element itself. The second is the index of the element. Third is an array of details about the selector itself (more about that in a minute), and the last item is a NodeList of all elements being evaluated.

In this particular instance, our selector array looks like this:

[":exactly", "exactly", undefined, undefined]

We see it has a reference to the filter, the term used in the filter, and then two undefined values. If we were to modify our filter a bit to accept a parameter, we would see the following:

$("div:exactly(Foobar)");
[":exactly(Foobar)", "exactly", "", "Foobar"]

The first value is our entire selector. The second is our filter name, third in this case is empty (though if we wrapped our term in single quotes, this entry would be a single quote as the outer-most single-quotes would be removed from the last item in this array), and last is the actual parameter passed in. Armed with this knowledge, we can then finish our custom filter:

$.extend($.expr[":"], {
    exactly: function( element, index, details, collection ){
        return $(element).text() === details[3];
    }
});

At this point, we can now select any element based on its text value:

$("div:exactly(foo), p:exactly(bar)");

We now have a reusable solution to a common task.

Sometimes jQuery is (not) the Answer

It’s difficult to say, as much as I love jQuery I must admit that it is at times the wrong route to take when addressing a problem.

While looking over a few questions on StackOverflow today I came across a poster who was seeking to modify the width of all nested elements within a container – he naturally thought jQuery would be a good, simple solution – and it is. But while it may be simple, it’s wrong in this case.

Rather than coming right out and answering with something like:

$("#container").find("*").width("100%");

I instead took just a moment to whip up a test case on http://jsperf.com (great site for testing the performance advantages of one method over others.) Just as I had suspected, jQuery would be slower than raw JavaScript – much, much slower.

var i,
    container = document.getElementById("container"),
    tags = container.getElementsByTagName("*"),
    total = tags.length;

for ( i = 0; i < total; i++ ) {
  tags[i].style.width = '100%';
}

This simple block does the same thing as the aforementioned jQuery code, but it’s much faster. In fact, in the time it takes the jQuery code to perform 20k operations, the raw JavaScript code performs nearly 300k!

You can see this particular performance test online at http://jsperf.com/resizing-children.