Thursday, June 27, 2013

jQuery UI: Check If Icon Exists

I like the way jQuery UI icons work. You just need a class, generally named after the thing the icon represents, and that class points to a specific location of an image. This approach supports extensibility. You add new icons to the theme images, and add new icon classes that point to them. While this is very useful, I couldn't help but wonder — how to we make sure that the icon actually exists before using it? For example, the jQuery widgets themselves aren't aware of which theme is in use, but if you're adding non-standard icons to one theme, but not another, this capability could be handy.

So, I took some ideas and implemented a simple function to test for an icons existence. Here are two spans, one with invalid icon data.

<span data-icon="plus"></span>
<span data-icon="not-found"></span>

And here is the function, used to validate each icon before it's used.

$(function() {

    // Returns true if the specified icon class exists
    // in any of the stylesheets.
    function iconExists( icon ) {

        if ( !document.styleSheets ) {
            return false;
        }

        var exists = false;

        // Iterate over each stylesheet.
        $.each( document.styleSheets, function( i, v ) {

            var rules = v.rules || v.cssRules;

            // Iterate over each rule in the stylesheet.
            $.each( rules, function( i, v ) {

                var selector = v.selectorText;
                
                // Does our icon class exist?  If so, exists
                // is set to true, and we exit the iterator.
                if ( selector.indexOf( icon ) !== -1 ) {
                    exists = true;
                    return false;
                }

            });

            // Icon exists, stop iterating stylesheets.
            if ( exists ) {
                return false;
            }

        });

        return exists;

    }

    // Get all spans with icon data.
    $( "span[data-icon]" ).each( function( i, v ) {

        var $icon     = $( v ),
            iconClass = "ui-icon-" + $icon.data( "icon" );

        // Only add the icon class if it exists.
        if ( iconExists( iconClass ) ) {

            $icon.addClass( "ui-icon " + iconClass );

        }

    });

});