Chicken Scratches

Making a Facebook app (with Django) – part 2: JavaScript and FBJS

Welcome to the second part in my series of posts about creating
a Facebook application. I am using Django as my web development
framework, but this post doesn’t have much to do with Django,
since it deals with the front end. In particular, it talks about
how to write JavaScript that can work both in and out of
Facebook.

As I mentioned last time, Facebook lets developers use a subset
of JavaScript, which they call FBJS. The FBJS is transformed on
the fly into JavaScript as the page is loaded. All variables and
functions you define or reference are prepended with a string
like “a123456789_”, including calls
to document.getElementById
and setTimer and the like. This is
done in order to restrict what you can do with DOM elements, to
avoid cross-site-scripting attacks and unwanted user-hostile
behavior. FBJS is fairly well documented, so if you plan to do
some Facebook JavaScript development, you should start there.

The biggest restriction that FBJS imposes is that you can no
longer access the attributes of DOM elements directly, but must
go through an abstraction API consisting of a series of setters
and getters. For example, instead of saying something like
imageEl.src = myImageUrl, you instead need
to call imageEl.setSrc(myImageUrl).

This is not too big of an adjustment, if you are accustomed to
writing raw JavaScript. It actually has some advantages, because
FBJS abstracts away some of browser-dependent aspects into a
standard API.

The challenge, however, becomes apparent when you try debugging
your JavaScript. With Internet Explorer and its horrendously
useless error messages and debugging facilities, it’s pretty
much hopeless, since the line numbers don’t correspond to line
numbers in your source code. However, even with Firefox and the
wonderful Firebug debugger, all the name mangling and rewriting
makes tracking down problems more difficult. Ideally you would
want to debug as much as possible outside of Facebook,
before then testing on the real site.

To make this easier, I developed some useful code to simulate as
much as possible the FBJS environment when running locally or
outside of Facebook. The idea was to re-create all the accessor
functions on all DOM objects. You can download the file
here
. You’re free to use it, but please don’t link directly to
the file on my site – copy it to your site and use it there. And
read the description below first.

I considered several different approaches before settling on the
final version. I considered trade-offs of performance and
possible side-effects. Rejected approach number one was to
modify Object.prototype to contain the new getters and
setters. This would have been the fastest, but can cause
problems with code like the following:

for (var param in obj) {
  // Do something with obj[param]
}

This would end up enumerating all of the added functions as well
as the properties of the object in question. This is why it is
generally considered a bad idea to modify Object.prototype.

The second rejected approach was to create a wrapper class with
all the accessor functions, that performs the requisite getting
and setting on a member variable containing the actual DOM
object. This one could have worked well, but it would have been
a lot of code to implement, and would have made debugging with
Firebug more difficult because of the added layer of
indirection.

The approach I settled on was to simply provide wrapper
functions for document.getElementById and
document.createElement, and for each element that is “getted” or
created, to copy in the required member functions. This has a
perfomance penalty during the getting or creation of elements,
but the calls themselves are speedy. There is likely to be a lot
more manipulation than getting, I would think.

How to use this code

To use this code, just reference this file from your web page
before any of your own JavaScript, but only when you are outside
of Facebook. Make sure to call fbGetEl and fbCreateEl instead of
document.getElementById and document.createElement. In the
version of your page that is intended to be run inside of
Facebook, include this code:

function fbGetEl(elId) {
  return document.getElementById(elId);
}
function fbCreateEl(elType) {
  return document.createElement(elType);
}

Alternatively, if you are feeling a little tricky, you can add
in some code like this to the end of fbHelper.js

document.getElementById = fbGetEl;
document.createElement = fbGetEl;

Then you can continue to use document.getElementById and
document.createElement. (Note that I have not tested this
approach.)

I hope this comes in handy for some people.

More FBJS tips

Beware of the cache!

If you make a change to your .js file and
don’t notice any difference in your app’s behavior, chances are
you are getting bitten by the cache bug. To get around this,
Facebook recommends adding “cache-breaker” code to the URL. For
example, instead of linking to “myFile.js”, link to
“myFile.js?v=2″. The extra text from the question mark on is
usually ignored by web servers for static files. In my Django
context processor, I have code like the following:

from svnVersion import svnVersion

# Add this function to your TEMPLATE_CONTEXT_PROCESSORS
# list in settings.py
def fbContextProcessor(request):
    return { # Add any other template vars you want here.
        'cacheBreaker':'?v=%s' % svnVersion }

Then in my template, whenever a have a link, I do something like:

<a href="http://example.com/myFile.js{{ cacheBreaker }}">Click here!</a>
    

Then every time I update my code, I run a shell script that does
something like:

      #!/bin/sh
      echo "svnVersion = '`svnversion -n .`'" > svnVersion.py
    

That way, every time I update my code, I make sure to break the
Facebook cache. Alternatively, you could call svnversion
straight from Python.

console.log is your friend!

This is true in general when
JavaScript programming, but especially so with Facebook. Take
the time to put in some extra logging messages while you’re
developing, and testing and debugging will be much easier. And
read up on Firebug as much as possible.

Check out the Animation library.

It’s pretty cool, and it works outside of Facebook, too.

Beware the limitations.

Facebook only allows up to five external
script files, so keep that in mind. You may unfortunately have
to combine two or more .js files into one to work around this
restriction. Also, FBJS doesn’t run on profile pages until the
user has interacted with the app.

Track comments by RSS

2 Responses to “Making a Facebook app (with Django) – part 2: JavaScript and FBJS”

  1. [...] Making a Facebook app (with Django) – part 3: Python & FBML Chicken Wing Software Resume Get in touch Chicken Scratches Page style (CSS): artistic elegant modern (Javascript required) « Making a Facebook app (with Django) – part 2: JavaScript and FBJS [...]

  2. Rey Bumalay says:

    I’ve been trying to solve this problem last night. I’m developing application for facebook running on app engine platform.

    Anyway I’ll try this a little later. Thanks for your article!

Leave a Reply