views:

210

answers:

1

I'm trying to write a Greasemonkey script for Facebook and having some trouble with the funky page/content loading that they do (I don't quite understand this - a lot of the links are actually just changing the GET, but I think they do some kind of server redirect to make the URL look the same to the browser too?). Essentially the only test required is putting a GM_log() on its own in the script. If you click around Facebook, even with facebook.com/* as the pattern, it is often not executed. Is there anything I can do, or is the idea of a "page load" fixed in Greasemonkey, and FB is "tricking" it into not running by using a single URL?

If I try to do some basic content manipulation like this:

    GM.log("starting");
    var GM_FB=new Object;
    GM_FB.birthdays = document.evaluate("//div[@class='UIUpcoming_Item']", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
    for (i = GM_FB.birthdays.snapshotLength - 1; i >= 0; i--) {
       if (GM_FB.birthdayRegex.test(GM_FB.birthdays.snapshotItem(i).innerHTML)) {
          GM_FB.birthdays.snapshotItem(i).setAttribute('style','font-weight: bold; background: #fffe88');
       }
    }

The result is that sometimes only a manual page refresh will make it work. Pulling up the Firebug console and forcing the code to run works fine. Note that this isn't due to late loading of certain parts of the DOM: I have adding some code later to wait for the relevant elements and, crucially, the message never gets logged for certain transitions. For example, when I switch from Messages to News Feed and back.

+1  A: 

Aren't they using ajax to load content in a div? You can find the element which is being updated by using Firebug for example.

When you click something and the URL changes, but with a # on the URL and after this some text, it means the text is not a path, it's a parameter, the browser won't change the page you are, so since GreaseMonkey inject the script on the page loads it won't inject again, because the page is not reloading. As in your example the URL facebook.com/#!/sk=messages is not navigating away from facebook.com/ it will not fire window.load event. So you need to find which element is being changed and add an event listener to that element, you can do is using Firebug as I mentioned before.

After you find out what element is getting the content, you have to add an event listener to that element and not the page (GreaseMonkey adds only on the window load event).

So in you GM script you would have ("air code")

document.getElement('dynamic_div').addEvent('load', /*your script*/);
BrunoLM
Most of the stuff I checked looked like normal links, but they append stuff to the URL GET parameters rather than change (i.e. it always stays as facebook.com/?blahfoo). For some reason I don't seem to get another GM execution when this happens.
Sam Brightman
Does it have a `#` on the URL? The page URL can change but won't reload the page. There is no other way to do it executing scripts from a website.
BrunoLM
Would a server-side redirect also stop GM from running in this case? e.g. load FB fresh, Messages href is facebook.com/?sk=messages but when you click it goes to facebook.com/#!/sk=messages and GM doesn't run. That would explain part of the problem.Of course, it's also messing with my setTimeout (and I'm not making the function name as string mistake) to check for elements arriving. Bit of an awkward site to script.
Sam Brightman
Ok, so this explains most of it. An additional issue is that by keeping the DOM elements around but not showing, DOM sub-elements don't seem to trigger insertion events, so you have to look for each "type" of reload individually. Still don't know why sometimes it seems to not reload (using #) but then fire the GM script as if it did, whereafter a setTimeout within it fails. If you add an answer to the effect of "duh, it's the # anchor", I'll accept and sort this final thing separately.
Sam Brightman
Ok, I will also add the URL you mentioned as an example.
BrunoLM