Thursday, May 1, 2008

Prototype JS incompatibility with Facebook JS client library

I have been working on a facebook application using their all new JavaScript client library. I was trying to reuse a large self-contained module that relied heavily on prototype & scriptaculous JS libraries. The module was working just fine outside the context of the Facebook application. But after including the Facebook JS library, runtime JS errors began to appear, especially when initiating a scriptaculous effect. Obvoiusly, that was concluded to be a compatibility issue between the prototype & scriptacuolous family on one side, and Facebook JS client library on the other.

The origin of incompatibility, courtesy of Mohammad Ali, was discovered to be a tiny bug in Prototype's browser identification. To the point, the problem was discovered to be as follows:
  1. Prototype identifies the browser as IE according to the presence of the IE specific function 'attachEvent'. In prototype.js line 13:
    IE: !!(window.attachEvent && !window.opera),
  2. Obviously, this condition is fragile, and will fail if any other included script defines a "window.attachEvent" function for any other browser, which is the exact case of Facebook JS client library.
  3. The Facebook library contains thefollowing line (FacebookApi.debug.js line 387):
    if (window.navigator.userAgent.indexOf('Safari') >= 0) {
    _loadSafariCompat(window);
    }
    else {
    _loadMozillaCompat(window);
    }
    This code is embedded in an if-condition that it is only executed if the browser is not IE.
  4. The function "_loadMozillaCompat" defines "window.attachEvent" for mozilla browser type, which causes Prototype's IE identification condition to fail, leading to a total mess up in many cases.

    The solution is to power up Prototype's IE identification condition, by adding a check that the browser is not mozilla. The new condition looks like that ( and it works :) )
    IE: !!(window.attachEvent && !window.opera && navigator.userAgent.indexOf('Gecko') == -1),
This will do it for this specific incompatibility instance. However, the sure thing is that the foundation of Prototype's browser identification needs a basic tweak to be concrete against other libraries.

No comments: