Front-end development feeds to follow

March 1st, 2010

If you're running low on front-end oriented stuff to read, I've got 130 exactly 200 feeds of high quality for ya.

google reader bundle

I've republished this as a google reader bundle, for easy subscribing.

If you use another feed reader, you can import them via the OPML file: frontendfeeds.xml

2010.07.07: Updated to google reader bundle. added 70+ feeds

How to fulfill your own feature request -or- Duck Punching with jQuery!

February 23rd, 2010

Wait, what? Well first, duck punching is another name for monkey patching. Monkey Patching is a technique to "extend or modify the runtime code of dynamic languages without altering the original source code." But then some Ruby hackers decided that since we rely on duck typing so often, a more proper name was in order:

… if it walks like a duck and talks like a duck, it’s a duck, right? So if this duck is not giving you the noise that you want, you’ve got to just punch that duck until it returns what you expect.[1]


In jQuery we can use this to great effect. We'll employ an AOP-like approach (aspect-oriented programming), maintaining the original function but wrapping it with our enhancement.

Example 1: Adding color support

(This is a silly example, but hopefully it explains the idea. )
You're fully aware that you can use certain color names in HTML. But sadly, everyone's favorite Crayola™ color, Burnt Sienna, can't play along. Well, not until now…

(function($){
 
    var _oldcss = $.fn.css;
 
    $.fn.css = function(prop,value){
 
        if (/^background-?color$/i.test(prop) && value.toLowerCase() === 'burnt sienna') {
           return _oldcss.call(this,prop,'#EA7E5D');
        } else {
           return _oldcss.apply(this,arguments);
        }
    };
})(jQuery);
 
// and using it...
jQuery(document.body).css('backgroundColor','burnt sienna')

Let's walk through that a little bit slower, shall we?

First we start off with a self-executing anonymous function that makes a happy closure while remapping jQuery to $:

(function($){
    // ...
})(jQuery);

Now we save a reference to the old css method as a local variable, and set up our new definition for that method:

    var _oldcss = $.fn.css;
 
    $.fn.css = function(prop,value){
        // ....
    };

Inside our function definition we have an if statement that breaks up two code paths, the new enhanced route, and the old default:

        // if the user passed in backgroundColor and 'burnt sienna'
        if (/^background-?color$/i.test(prop) && value.toLowerCase() === 'burnt sienna') {
 
            // call the old css() method with this hardcoded color value
            return _oldcss.call(this,prop,'#EA7E5D');
        } else {
            // otherwise call the old guy normally, taking his return value and passing it on.
            return _oldcss.apply(this,arguments);
        }

Scroll back up to see the whole thing together. Can you dig it?

Example 2: $.unique() enhancement

$.unique only winnows an array of DOM elements to contain no duplicates, but what if you want all non-duplicates of any type? Here's an upgrade:

(function($){
 
    var _old = $.unique;
 
    $.unique = function(arr){
 
        // do the default behavior only if we got an array of elements
        if (!!arr[0].nodeType){
            return _old.apply(this,arguments);
        } else {
            // reduce the array to contain no dupes via grep/inArray
            return $.grep(arr,function(v,k){
                return $.inArray(v,arr) === k;
            });
        }
    };
})(jQuery);
 
// in use..
var arr = ['first',7,true,2,7,true,'last','last'];
$.unique(arr); // ["first", 7, true, 2, "last"]
 
var arr = [1,2,3,4,5,4,3,2,1];
$.unique(arr); // [1, 2, 3, 4, 5]

A Duck Punching Pattern

Here's the bare pattern. Feel free to use this as the basis of your own:

(function($){
 
    // store original reference to the method
    var _old = $.fn.method;
 
    $.fn.method = function(arg1,arg2){
 
        if ( ... condition ... ) {
           return  .... 
        } else {           // do the default
           return _old.apply(this,arguments);
        }
    };
})(jQuery);

What else could I use this for?

Some other uses I've had or seen for this sort of thing:

So while you're free to file a feature request of jQuery, most of the time you can actually enhance jQuery's methods yourself! Enjoy.

On jQuery's live()

January 22nd, 2010

Since the release of 1.4, there's been a lot of discussion about live(). Now that it's almost as fully featured as bind(), it's getting quite a workout.

One of the larger calls to action is to introduce $.live(selector,eventType,handler). There are two primary reasons I've seen behind this proposal:

  1. There is a performance hit for the initial selection in $('a.whatever').live(.. that isn't neccessary
  2. live() cannot work on any arbitrary collection of DOM elements in jQuery object, as a side effect of a very different internal operation, thus providing an inconsistent developer experience than all other $.fn.foo methods.

$.live for performance

Sizzle is used to find any matching elements before the live method discards them an only uses the jQobj.selector property and context. It's a waste, I agree. But you can avoid it. Zachleat posted this technique first. Then I stole a code snippet from @janl to show off in my jQuery Performance talk for jQCon. This inspired furf's jQuery.live() patch. And now jmar777 has resurrected that discussion.

I do not think the performance gain in $.live is worth adding it to jQuery core, by any means. Let's take an example.

Let's say we're dealing with $(selector).live('click',fn)

On every click on the page, the event is caught at the context.. the document. But evt.target points to the top-most element that was clicked on.
jQuery then traverses from evt.target through each ancestor of that node all the way up to document checking if (jQuery(elem).is(selector)).[source]

I think a reasonable estimated depth of evt.targets is like 8 (From the document to HTML element to BODY and so on.. a depth of 20 is not uncommon by any means). And lets say we have an average 5 clicks on a page.
That's 40 total checks against the selector (plus the original one done at bind time).
So in my opinion a 1/41 speed gain isn't worth changing the API.

Scoping the delegation a context, however has a much larger impact on performance: $(selector,elem).live('click',fn) Here, only clicks within the context are caught, so not only is the parent traversal depth much more shallow, but that entire sequence is avoided for all events occurring outside that area.

The current API to take advantage of this optimization requires code like $('a.awesome', $('#box')[0]).live(… Yuck! So I wrote a patch to deliver this same optimization to any ID-rooted selectors. (The perk being that everyone who learns #id-rooted selectors are fast for selecting get a related perf boost here). But as Justin Meyer pointed out in the comments, it's not as flexible as live() currently is.

$.fn.live cannot operate on any jQuery-wrapped collection of elements

$('a.foo').filter('.bar').live(... // fails
$('a.link').parent().nextAll().live(... // fails
$(this).live(... // fails

Quite simply, $.fn.live needs to be at the top of a chain to guarantee the .selector and .context properties of the jQuery object represent that set. Unlike other $.fn methods, live utilizes those properties and not the actual collection of elements that result from selection, traversing, and filtering.

$.live() and let $.die()

What are the possible solutions?

  1. Turn on a dirty flag in traversal methods, so if you try and live() that collection, it will throw an error.
  2. Deprecate $.fn.live and use $.live(selector[,context],type,handler)
  3. Use $.live to create a "live jQuery object" that defaults to live-bindings: $.live(selector,context).click(fn).mouseenter(fn).unbind("click") [source]
  4. Change $.fn.live to operate from a context: $(context).live('selector', event, fn) This bakes the performance benefit from above right in.

Any others? What do you guys think? Is there a solution that preserves backwards-compatibility while solving the issue?

btw- thx to jmar777, yehuda katz, ben alman, ajpiano, brandon aaron and julian aubourg for their great thoughts on the issue.

The people in this discussion got together and hashed out what would make sense. John Resig then landed a new delegate/undelegate API. It's good. :)

Updates from all around - Dec 2009

December 19th, 2009

A lot of the work I'm doing doesn't turn into new posts so here's a summary of what's been going on:

yayQuery

Since it was announced here, we've come a long way. We just put out our 7th episode (now in HD!). The show format has tightened up and we're putting a lot of time into making it even better. Follow us on twitter or subscribe to catch all the goodness. We also put out an entire episode devoted to what's coming in jQuery 1.4 (aka 1.MOAR), so peep it if you're curious.

jQuery Singalong plugin

I was a finalist at Boston's Music Hack Day with the jQuery Singalong plugin. It essentially allows you to add timed annotations to the HTML5 audio and video elements. (Also it was the first time I legitimately used javascript's Infinity :) In addition, I put out the (very!) alpha jQuery Bouncing Ball plugin. Check out the demos to get a taste

Modernizr updates

Faruk and I pushed out Modernizr 1.1, which can now detect what audio/video formats your browser supports, all sorts of HTML5 forms goodness, and some other ones like localStorage and applicationCache. We're delighted to be part of Mark Pilgrim's Dive into HTML5 book and pumped to help push the edge of progressive enhancement.

@font-face and webfonts

It's a rapidly changing landscape, so I've been keeping all my font-y posts up to date:

@font-face feature detection

I've updated the existing feature detection script to use a smaller file. (Thanks to the Font Squirrel for the help). You would use this script to detect if support is present or not; perhaps implement a Cufon fallback. These new improvements will make their way into Modernizr 1.2.

I've also added on a isFontFaceSupported browser sniffing alternative. The main benefit here is that you're guaranteed accurate results synchronously. (The true feature detection can't do that, though the new small size is much faster in Firefox.)

Other bits and bobs

The nice guys at that other jQuery Podcast had me on the show in November. I talked about, well.. basically all of the stuff above. :) It's a good show.

I tweeted about a new quick approach to a for loop:

for (var i = -1, len = arr.length; ++i < len; ) // the cool guy loop

The fun part is that the counting expression (the third part) is empty. It's faster than your standard loops, but reverse while() is still quicker. @jdalton beat me to this one, for the record.

Lastly, along with my writers, I've been keeping my mp3 blog Aurgasm fresh with new music you'll love. I've got a lot more things in the pipeline, so right after my Christmas and New Years jaunt around Germany, Denmark, and Scotland, you'll see them soon. Happy December ya'll.

Memorable hex colors

December 4th, 2009

Hopefully this will save you a trip back to Photoshop's color picker.

  • #b00b00
  • #de1e7e
  • #e1e100
  • #BADA55
  • #F0FEAF
  • #ac1d1c
  • #facade

These ones are memorable, but not terribly color-appropriate:

  • #c0ffee
  • #defec8
  • #deface
  • #0ff1ce
  • #a55

Thx for the awesome suggestions: @mrspeaker, @8centsaday, @wilto, @lrbabe, @twalve
If you have any good ones to add, holler in the comments!

I guess I have a thing for hex colors.. ;)

i left this space here for you to play. <3