Matt Langer

I also do a twitter.

Aug 10 2009

KEEP SCROLLING.

So in the office on Friday I pulled off this epic hack that was at once so poignant and so profound and yet so thoroughly soul-crushing that it took me somewhere in the vicinity of eight vodka drinks after work to erase those roughly six hours from my memory, during which time I sent a text message to Mills reading “HI I GOT YOUR PHONE NUMBER FROM AN EMAIL SIG BECAUSE I REALLY WANTED TO DRUNK TEXT YOU TO TELL YOU YOU’RE MY FAVORITE PERSON IN THE WORLD. XOXO, LANGER” and after which my phone promptly rang resulting in Mills and I speaking for the very first time ever for a duration of around twenty-five minutes in a sweeping fairy tale of bromance (and during which, I should not fail to mention, it was revealed to me that my blogging efforts have received the vaunted Mills’ Dad Seal of Approval [ed note: high-pitched squealing]).

Yet earlier in the evening before any of this had gone down it had occured to me that maybe because the sum total of my charity efforts consists of occasionally bumming cigarettes to drunk people and/or homeless bums it might behoove me to blog about my hack since surely there was some other poor schmuck out there who was either presently enduring or would one day endure the same torment I’d just overcome, but at first I thought that maybe I shouldn’t blog about it because it might be in conflict with my “personal brand” and then I was reminded of what a man far wiser than myself once told me over email regarding a matter he and I both had in common, a matter that he had considered blogging about but refrained from because “that would have damaged [his] key tumblr demographic of girls who are too hot to be interested in things that [he] find[s] interesting” and, well, anything for the ladies.

However, I arrived at my desk this morning to discover that our version control system had mysteriously lost all traces of the code I’d checked in on Friday evening and that I’d have to not only remember the hack but I’d have to write the code a second time because OH GODDAMNIT IF ONLY I’D BLOGGED ABOUT IT LADIES BE DAMNED etc.

Once bitten twice shy and all, so here it is.

So we use this busted-ass pounded-URL system (a la Gmail) because we use a bunch of Flash that (shoot me in the face) can’t ever be unloaded from the DOM, and so (VICOTIN PLEASE) all of our content and page transitions come by way of late-loaded AJAX calls. Tangentially, we’ve also recently begun implementing the Facebook Connect and Facebook OpenStream APIs, with the intention of using the XFBML friend selector in a few places. One small problem: so far as all our testing revealed, and so far as everyone on the internet seems to be in agreement on, the friend selector cannot be included in a template rendered on the server side because the call to FB.XFBML.Host.parseDomTree(); can’t recognize the late-loaded AJAX content. This means that the only way to incorporate the selector is by way of Facebook’s embeddable <iframe>, which sucks in no small part because it forks the user flow and results in the final click spawning a new window which isn’t the end of the world but kind of sucks when you’re trying to build idiot-proof websites.

But not everything you read on the internet is true, it turns out: it’s not Facebook or AJAX to blame but probably just your JavaScript framework. In our case (JQuery), the overridden DOM manipulation methods were butting heads with Facebook’s JS which led us (and the rest of the internet, apparently) to conclude that DOM-injected pre-rendered FBML was simply a non-starter.

So here is Teh Hack™:

// this shit has nothing to do with my hack,
// I just include it here to remind you
// that you're going to need it

<script type="text/javascript"
src="http://static.ak.connect.facebook.com
/js/api_lib/v0.4/FeatureLoader.js.php">
<script type="text/javascript"> 
FB_RequireFeatures(["Connect", "XFBML",
"CanvasUtil"], function() {
    FB.Facebook.init("YOUR_FACEBOOK_KEY", 
    "http://YOUR_SERVER/xd_receiver.html");
});
</script>

/**********************************
 *  OMG R U READY 4 THIS??!?!!?!  *
 **********************************/

<fb:serverfbml style="width: 582px;"> 
  <div id="hack_part_one"> 
  </div> 
</fb:serverfbml> 

<div id="hack_part_two"> 
    <fb:fbml> 
      <fb:request-form 
        action="http://whatever" 
        method="GET" 
        invite="true" 
        type="Whatever" 
        content="Whatever 
        <fb:req-choice url='yourURL' 
label='Whatever'/>"> <fb:multi-friend-selector showborder="true" actiontext="Whatever." cols="3" bypass="cancel"></fb:multi-friend-selector> </fb:request-form> </fb:fbml> </div> // PAY ATTENTION // THIS PART IS IMPORTANT <script> new_elm = $('<script>'); new_elm.attr('type', 'text/fbml'); new_elm.attr('text', $('#hack_part_two').html()); $('#hack_part_one').replaceWith(new_elm); $('#hack_part_two').remove(); // FFFFFFUUUUUUUUU MARK ZUCKERBURG FB.XFBML.Host.parseDomTree(); </script>

Yeah, so here’s the deal: create two separate DIVs, one which is just a dummy placeholder (“hack_part_two”) that exists solely to get your rendered FBML from the server and another (“hack_part_one”) which is going to hold your actual script data once all is said and done.

After your template has been rendered on the server and injected into the DOM the script at the bottom will execute which a.) creates a new “<script>” element, b.) sets the appropriate type to the script (which must be “text/fbml”), c.) assigns as its contents the existing contents of “hack_part_two” (which was just for the temporary storage of our script during the AJAX transfer), d.) swaps the contents of the two hack divs and destroys the latter, and finally e.) tells Mark Zuckerburg to parse the DOM tree.

And since this is something I’ve always wanted to say but don’t write an engineering blog and have never had occasion to: how and/or why this works is left as an exercise for the reader.


  1. jhnbrssndn reblogged this from langer
  2. nudawn reblogged this from langer
  3. langer posted this