Automatically Expand Facebook “Older Posts” Links

EDIT: Sadly, although not entirely surprisingly, this doesn’t appear to work any more. Facebook is constantly changing the layout and content of their various pages, and I have no real intention to keep up with them. However the code may be useful for someone else to modify at any point in time to work on the current version. Sorry!


This evening I had that not-uncommon need to track down some dusty old Facebook comments from a couple of years ago. Naturally, Facebook makes it difficult to see anything more than a week old, but if you keep clicking “Older Posts” at the bottom of your (or a friend’s) Wall for long enough, you can see all posts back to the beginning of time.

This is kind of nice, but very tedious. Surely there’s a way to automate this process? I’ve seen numerous attempts, but many are either too complex for such a simple task (such as the sprawling Social Fixer browser extension), or too simple for the ever-changing complexities of Facebook. I decided to take a couple of pointers and put my new-found jQuery skills to a quick test. The result: FBExpand, a simple tool for a simple purpose.

The code is up on Bitbucket for inspection, but to put it to work right away it’s much easier to use this bookmarklet: FBExpand. Drag that link to your bookmarks bar, and simply click it when you want to expand some Facebook history (e.g. when viewing your Wall). Too easy!

The code

(function(){
// The text in the link you wish to automatically expand.
var expandText = "Older Posts";
// Timer delay (ms) between 'clicks'. Set to roughly the time it takes to load
// the next link text. May need to increase value for slower connections.
// Too short may freeze the script, however too long will waste time.
var delay = 1500;

These couple of lines allow for some minimal customisability. The script locates the link button based on the text within it, chosen by the expandText variable. This strikes me as more future-proof against Facebook’s endless interface changes than an otherwise more precise approach of drilling down the DOM or picking out element IDs and classes. The delay variable is more or less explained by its comments.

/*
Reduced from Karl Swedberg's jQuerify bookmarklet script at:

http://www.learningjquery.com/2009/04/better-stronger-safer-jquerify-bookmarklet/

*/
// Ensure jQuery is available as $jq

(function(){
if(typeof jQuery!='undefined'){$jq=jQuery; return;}
var head=document.getElementsByTagName('head')[0],done=false;
var script=document.createElement('script');
script.src='http://code.jquery.com/jquery-latest.min.js';
script.onload=script.onreadystatechange=function(){
if(!done&&(!this.readyState||this.readyState in ['loaded','complete'])) {
$jq=jQuery.noConflict();
script.onload=script.onreadystatechange=null;
head.removeChild(script);done=true;
}
};
head.appendChild(script);
})();

This block is simply Karl Swedberg’s jQuerify script reduced to its bare bones (i.e. removing the visual feedback). It ensures that the jQuery library is loaded and bound to the variable $jq before proceeding. Read his post for an explanation; it’s about the third version, and it’s quite neat.

// Keep clicking the links until there's none left
var loop = setInterval(function() {
var a = $jq('a:contains("'+expandText+'")');
if(a.length) eval(a.attr('onclick').split('return')[0]);
else {clearInterval(loop); console.log("All posts expanded.");}
}, delay);
})();

Here’s my stuff – it looks awfully straightforward after all that. Essentially, it follows a few simple steps, outlined below. Since the code is wrapped in a setInterval() function call, it is called again every delay milliseconds. This allows Facebook a little time to load the next batch of posts before performing another click.

  1. Find the expand link based on the text contained within it using a jQuery DOM selection.
  2. If the link exists, grab its onclick code and execute it, effectively emulating a user’s mouse click. For some reason simply calling .click() on the jQuery object wasn’t working, so this was my workaround.
  3. If the link doesn’t exist, there’s nothing to expand, so the script ends, putting a stop to the repetitive interval execution and printing a simple debug message to the browser’s console.

Thoughts

This little exploration has done little to change my perception of JavaScript as a rather hacky approach to software development. Of course, any language can only be as elegant as the task (and developer) allows, and if you’re trying to do hacky things like this, then JS/jQ are fantastic. As far as modern web UI design goes however, I’m still looking forward to spending some quality time learning Dojo in the future. Coupled with Backbone.js, it looks like a very powerful tool for any serious web development.

Naturally, such a tiny script should be very possible without any jQuery-like library. In retrospect, the only thing I use it for is to select the expand link node. Perhaps I’ll rewrite it tomorrow to do that in standard JS and cut the script in half. It’s all good practice, in any case.

Finally, my efforts went somewhat unrewarded, since I didn’t find the exact post I was looking for. I realised too late that it was a comment on an activity (Liking a Facebook page) rather than on a post. Since activities aren’t really shown on one’s Wall the same way any more, neither that Like or its comments could be found. If anyone knows how I might be able to locate something so specific, please let me know! I’ll own you one.

Holiday Direction

The updates have been fairly sparse recently, but as Christmas (or equivalent) approaches everyone gets pretty busy. Fortunately, a few of the things I’ve been very busy with are Piemaster-related: I’m breaking some new ground with Forgbook and Buffex, and exploring a couple of other potential projects on the side.

Forgbook has received a lot of competition lately, as numerous development teams small and large have release highly polished task management applications, such as AsanaDo.com and Orchestra. Many of these have a strong emphasis placed on collaboration across tasks, but still none offer the ability to arbitrarily break down tasks into subtasks. This seems like a pretty fundamental thing to want to be able to do, and is of course the cornerstone of Forgbook.

However all of these applications do offer very slick user interfaces, and to at least be competitive, I’ve realised that Forgbook requires a modern makeover. As such, I’ve finally taken on learning some JavaScript properly, because against my wishes it has undoubtedly become the modern web’s lingua franca. I’ve been mocking up a few single-page AJAX applications with the very handy Backbone.js library, which drastically simplifies (or at least provides structure to) the MVC design of the user interface. It’s quite reminiscent of my time with Adobe Flex, minus the constant annoyances of Flash, and I’m hoping to write a bit about it once I’m a little more comfortable.

On that note, I’ve been approaching Buffex from a more modern perspective as well. I noticed I haven’t mentioned Buffex in a post before, and indeed the project page has been a rather misleading “Coming soon.” for the past year or so, but you’ll hear a lot more about it soon. Since the minimum viable product (MVP) incarnation of Buffex is relatively simple, I’ve decided to focus my efforts on that for the time being before pressing on with Forgbook (which is looking much slicker than it used to, but has a lot of work to go). I’ll be taking a Backbone approach to Buffex too, to try and have nice, snappy interface and keep everything nice and simple.

That’s more or less where my head is at the moment. Those couple of other ideas I mentioned will get some more attention next year, but I can say that one of them has been born out of my recent fascination with gardening. If there are any gardeners out there, let me know! I’m trying to bring a rather unorthodox approach to it, and would love to discuss it with others. Techies tend not to be very enthusiastic garderners however, which is both a good thing and a bad thing in some sense. Regardless, I know I’m looking forward to it.