Google Voice Click-to-call Widget

1 comments

I'll keep this short. I was lucky enough to get in on the Google Voice closed beta (back when it was Grand Central). It offers a free click-to-call widget that you can embed in your web pages. But it didn't offer quite enough "pizzaz" for my taste, so I enhanced it a bit using some Javascript. I'm making the code freely available. (It should be an interesting read.)

It works in IE 6 through 8 as well as Firefox 3 and Safari 3. I didn't test it in anything else. To see it in action, use one of the aforementioned browsers and go to http://techhead.biz.

Feel free to use it, improve it, etc. As always, a little credit here would be appreciated. If you do use it, please leave a comment here and drop a link so I can find you.

DOMContentLoaded and ondocumentready and onreadystatechange! Oh my!

0 comments

How do you determine when your document is ready to be manipulated by the javascript in your web application? In the course of a recent project, I discovered that the answer is perhaps not so simple as the question. In fact, the conclusion I've come to is that "it depends".

The most elegant solution I've come across (in my opinion) is the DOMContentLoaded event. This event has been hidden in Mozilla browsers since I don't know when (???) but has now been adopted in recent versions of WebKit and Opera as well. As the name suggests, this event fires when the document tree (DOM) is completely loaded. This may fire before images and other external objects are loaded. The only problem is that IE 6, 7 and 8 don't support it, so there goes the market share. The rest of this article is about various "hacks" which attempt to emulate this behavior in IE.

The current most popular workaround (and newest I believe) is a "hack" discovered by Diego Perini. It is based on the ondocumentready event that is available only to Behaviors in IE. Diego discovered a paragraph in an MSDN document and ran with it.

A few methods, such as doScroll, require the primary document to be completely loaded. If these methods are part of an initialization function, they should be handled when the ondocumentready event fires.

Taking the reverse of this statement, Diego tried polling doScroll until there were no more errors as a means to achieve a "poor man's" ondocumentready. And guess what? It works! ...Sort of. If the loading document's window is not top level (ie. if in an iframe), doScroll never errors and the hack falls apart.

// Should return true only if the document is ready, false otherwise
// Works unless in an IFRAME
function documentready() {
  try {
    window.doScroll('top');
    return true;
  } catch (e) {
    return false;
  }
}

function init() {
}

// Poll until documentready
(function() {
  if (documentready()) return init();
  setTimeout(arguments.callee, 0);
})();

Another popular method of DOMContentLoaded emulation in IE is the deferred SCRIPT method made popular by Dean Edwards.

function firedomload() {
}

// A deferred, external script is executed after the DOM is available in IE.
// I know of no formal specification for this behavior.
// However, it appears consistent across IE 6 through 8.
// MUST use a document.write to emit the SCRIPT (if being placed dynamically)
//   or readyState never reaches 'complete'.
//   (I don't know why, but that's just the way it is.)
document.write('<' + 'SCRIPT src="//:" defer><' + '/SCRIPT>');
var script = document.documentElement.lastChild.lastChild;
script.onreadystatechange = function() {
  if (this.readyState == 'complete') {
    this.onreadystatechange = null;
    this.parentNode.removeChild(this);
    firedomload();
  }
};

The problem with this method is, of course, is that it requires a call to document.write which will obliterate the current document if called too late.

Dean also shows us how to take advantage of the ondocumentready event directly, but this method requires an external HTC Behavior file, making it less friendly for inclusion within libraries.

Lastly is the most obvious option. Place a script after all of the content in the BODY of your document and use it to bootstrap the initialization calls.

<html>
<head>
<script type="text/javascript">
if (typeof ondomload == 'undefined') ondomload = [];
ondomload.push(function() {
  alert('This will execute on DOM load');
});
</script>
</head>
<body>
... some content ...
<script src="firedomload.js"></script>
</body>
</html>

And the firedomload.js script looks like this...

/**
 * This SCRIPT should be placed just before the close of the BODY element
 * in your (X)HTML document. It may be deferred.
 *
 * Scripts that take advantage of 'ondomload' may come before or after
 * this SCRIPT and may be either deferred or not deferred.
 *
 * USAGE:
 * if (typeof ondomload == 'undefined') ondomload = [];
 * ondomload.push(function() {
 *   alert('This will execute on DOM load');
 * });
 */
if (typeof ondomload == 'undefined') {
  ondomload = {};
} else {
  while (ondomload.length)
    setTimeout(ondomload.shift(), 0);
}
ondomload.push = function(cb) { return cb() };

In summary, each method has its pros and cons. Even the library authors can't agree on what is best. At the time of this writing, jQuery uses the doScroll method and Prototype uses the deferred SCRIPT method. I've written a small function using the deferred SCRIPT method. You can find it here. The source code for the tests is also available here. And there is a live test here.

What you use may depend on your needs.

Running IE6, IE7 and IE8 on your Mac (reloaded)

1 comments

The original article is here: http://blog.mozmonkey.com/2008/vpc-ie6-ie7-ie8-on-mac-os-x/

I came across the above article a while ago when looking for a good way to test my web sites in Internet Explorer without having to resort to using a PC. Microsoft releases Virtual PC images of Windows containing various versions of the Internet Explorer web browser. These expire and are re-released periodically. At the time of this writing, they are about to expire again. I do hope that Microsoft will continue this valuable service. (It's the least they can do.) You can download the images here: http://www.microsoft.com/downloads/details.aspx?FamilyId=21EABB90-958F-4B64-B5F1-73D0A413C8EF

If you are using Windows, then you may download the free Virtual PC from Microsoft. Otherwise, download the free, open source VirtualBox. At the time of the article noted above, it was necessary to first convert the Virtual PC images before they could be used on VirtualBox. This is no longer the case.

The Virtual PC images available from Microsoft come packed in self-expanding archive files. This is a small problem if on a Mac. You cannot run the self expander, but I find that the free Stuffit Expander works fine to extract the image file.

Once you set up your virtual machine, Windows will boot, show you the EULA and attempt (and fail) to install a bunch of "new hardware". Just skip past all of this and then choose "Devices -> Install Guest Additions..." from the menu bar. This allows better integration with your system. It also makes folder sharing with your Mac possible.

Of all those hardware installation dialogs you clicked past earlier, one of them was to install a network device. Without this, you can't access the internet. At the time of this writing, VirtualBox emulates an AMD PCnet-FAST III NIC by default. You will need to download the driver for it here. Then you'll need to setup a shared folder and put the driver in it so that you may install the driver from Windows.

If you're a more visual person, just watch the video here (or inline below).