jQuery doOnce plugin for chaining addicts

// jQuery doOnce plugin
jQuery.fn.doOnce = function(func){ 
    func.apply(this); 
    return this; 
}

This allows you to execute arbitrary script during a single chain. A bad example of alert() debugging follows:

// example usage of doOnce()
$('div.toGrow')
  .doOnce(function(){
    alert('before color swap');
  })
  .css({ backgroundColor: 'red'})
  .find('h2')
    .text('And now we\'re red')
    .end() // go back to the div.toGrow
  .animate({ height: '+=50px'},'normal','swing',function(){
    $(this)  // callback when animations complete
      .find('h2')
        .text('And now we\'re taller')
        .doOnce(function(){
          alert('animation done');
        });
  });

Note this is a little different than each(), which will execute once for every element in your current collection.
The code is pretty trivial, but sometimes you just feel like it. Nobody likes to break the chain!

How to tweak 3rd party scripts “safely”

I'm working with some code from MultiMap (basically a Google Maps clone), and unfortunately their API doesn't support real internationalization. There are a number of strings hardcoded in English in their remotely-hosted JS, so this is my deliciously evil way of rectifying the situation.

I first started out redefining their functions in entirety, but that becomes "dangerous" when they modify a bit of code for a bug fix or something. This revised approach slips in like an evil drunken ninja and only replaces the offending parts. It's still completely crazy, but sometimes there are no better options...

// WARNING!!  This is such a massive hack. Oh-so-hackalicious
 
// Problem:     Multimap doesnt allow internationalization of its buttons, etc.
// Solution:    Redefine their JS functions to use variables that are internationalized.
// Assumption:  That these internal function names stay the same. 
// Risk:        If function names change, this code will (probably) silently fail.
 
// The following statements change the right-click context menu items and the map/aerial/hybrid buttons.
// Instead of hard-coded strings, it will use a variable which we control.
 
// ON TO THE HACKS!!
// Hack 1: modify the mmjr() and mmfl() functions with funcName.toString().replace()
// Hack 2: use eval() to set the definition
// Hack 3: browser sniff because IE and FF handle toString()'d strings differently (single-quote vs double-quote)
 
var isIE = $.browser.msie; // jQuery browser sniff.
 
eval(
  "mmki.prototype.mmjr = " +  
  mmki.prototype.mmjr
  .toString()
    .replace( isIE ? "'Move map to here'" : '"Move map to here"' ,      'i18n.retailLocator.moveMapToHere')
    .replace( isIE ? "'Zoom in to here'" : '"Zoom in to here"' ,        'i18n.retailLocator.zoomInToHere')
    .replace( isIE ? "'Zoom out from here'" : '"Zoom out from here"',   'i18n.retailLocator.zoomOutFromHere')
  );
 
eval(
  "MultimapViewer.prototype.mmfl = " +  
  MultimapViewer.prototype.mmfl
  .toString()
    .replace( isIE ? "'Map'" : '"Map"',       'i18n.retailLocator.map')
    .replace( isIE ? "'Hybrid'" : '"Hybrid"', "i18n.retailLocator.hybrid")
    .replace( isIE ? "'Aerial'" : '"Aerial"', 'i18n.retailLocator.aerial')
);

The top 55 best front-end development RSS feeds

I've put together all the feeds and blogs that I follow that cover front-end development.
Here is the OPML file: front-end-development-feeds.xml.opml

feeds.pngAll the classics like Ajaxian and A List Apart are in here.. but also more technical ninja developers like John Resig, Hedgerwow and Peter Michaux.

If you currently use a RSS aggregator (like Bloglines, Google Reader, or Netvibes) you can import this file right in.
iGoogle won't take an OPML file but you can do each RSS feed individiually.

You can also preview what's in it here: http://www.bloglines.com/public/molecular-frontend-feeds

Graceful Degredation of Your Firebug-specific Code

// code yanked from the Yahoo media player. Thanks, Yahoo.
if (! ("console" in window) || !("firebug" in console)) {
    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group"
                 , "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
    window.console = {};
    for (var i = 0; i < names.length; ++i) window.console[names[i]] = function() {};
}

concatenate()

Updated 2008.01.28: Great idea from Marc and Hendrik. Very slick.

function concatenate(){
  // return arguments.join('');                      // won't work. arguments is not a real array.
  // return [].splice.call(arguments,0).join('');    // old 'n busted
     return Array.prototype.join.call(arguments,''); // new hotness
}
 
concatenate('good',2,'go');
// ==> 'good2go'

How to iterate quickly when debugging CSS

firebugscreen.PNGFirebug is my tool of choice to fiddle with CSS. I'll edit the elements on the page, and then copy my changes back to the .css file. Then save.

If you're in a webapp, refreshing the page could take a while, so here's a great way to reload the freshest copies of the stylesheets. Drag this bookmarklet link to your toolbar:

>>> Refresh CSS <<<

Clicking it will modify any <link rel="stylesheet"> tags and append a timestamp at the end of each href attribute, thereby dropping the cache and grabbing a new one. It's quick and beautiful.

You must restart your system

In the 10 years that I've seen dialogs like these, I've always clicked "No" or "Restart Later" and the software ALWAYS works. The software installs indicate it's mandatory, but never is it functionally mandatory. Not TortoiseSVN, ISO mounting utilities, not even Microsoft Office; it always works without a reboot.

So why is this pattern so widely adopted?

Automate firing of onload events

I've often had to set up onload events that execute for only a single page. I've both hardcoded those function calls right into the markup and I've done page detection in a shared js file (parsing the current URL, ew!). Neither solution is rather pretty. The below solution keeps things unobtrusive.

Set up the body tag with an ID that identifies the page, such as:

<body id="homepage">

Over in your javascript, set up your page init code in an object literal:

var siteNameSpace  = {
   homepage : {
      onload : function(){
         // do this stuff.
      }
   },
   contact : {
      onload : function(){
         // onload stuff for contact us page
      }
};

Your document ready code executes for the same for all pages:
jQuery:

$(document).ready( siteNameSpace[ document.body.id ].onload );

Prototype:

Event.observe(window, 'load', siteNameSpace[ document.body.id ].onload );

YUI:

YAHOO.util.Event.onDOMReady( siteNameSpace[ document.body.id ].onload );

However this will fail if that object (and onload function) are not defined.
But you can fix it with a little more code..

//jQuery version
$(document).ready( 
  function(){
    var NS = window.siteNameSpace, bID = document.body.id;
    if(NS && NS[ bID ] && (typeof NS[ bID ].onload === 'function')){
      NS[ bID ].onload();
    } 
  }
);

Javascript CSS Selector Engine Timeline

I'm interested in understanding all the selector engine code. In order to watch the development from the most basic to the quickest, I wanted to gather all the data points. Take a look, as you can see, Jack Slocum was definitely right when he said "selector processing power has gone from Pinto power to a Mustang GT 500."

Update: Added Base2, CssQuery1.0. Corrected jQuery launch date.
Update: Added Dojo 0.9, NWMatcher.

(Drag to navigate timeline)

Leave a comment if I left anything out.

Unobfuscating packed javascript

I started to get curious around Virb's code and wanted to take a peek at how they're doing some things.. Their global js didn't prove to be too helpful.. It was just packed and obfuscated: http://www.virb.com/_js/global.js
packedcode.PNG
In fact, a lot of javascript gets packed up these days with Dean Edwards amazing Packer functionality. This is great for delivery and optimization, but hard for people to poke in and learn some new techniques. I couldn't be so easily defeated by Virb's code.
Ryan at YAIB created a little bookmarklet widget to enable the decode functionality at dean's packer site.
Drag the reEnable link to your bookmark bar, then head over to the packer site and click the button. The "copy" textarea should now be writeable and the decode button activated.
Now copy in your packed and obfuscated code and hit decode.
If successful, you should now see some var's and null's and everything be looking a little more like readable javascript.
Head over to Pretty Printer, paste your decoded code in, select these settings...
prettysettings.PNG
and hit Submit Query.

You'll now have some nice looking javascript to inspect. Chees.