Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why greasemonkey doesn't detect some page changes in facebook?

I was trying to do a user.js to /messages page in facebook, but looks like greasemonkey doens't notice when the navigation changes from / to /messages. It also occurs in other internal pages. First i thought that it was caused by AJAX navigation, but the URL changes (not hash part), so it's normal navigation, right?

This is a test page that I used:

// ==UserScript==
// @name           Test
// @namespace      none
// @description    just an alert when page changes
// @include        http*://www.facebook.com/*
// ==/UserScript==

alert(location.href);

How can I correctly detect page changes?


Firefox version: 6.0.2

Greasemonkey version: 0.9.11

like image 688
Ravan Scafi Avatar asked Sep 11 '11 21:09

Ravan Scafi


2 Answers

For browsers that support it, including Firefox 4+, Facebook takes advantage of the HTML5 History API. This API allows the location to be changed using the history.pushState() method although no navigation actually occurs. Though the page may seem to have changed, all that's happened is a behind-the-scenes ajax call that changes most of the content.

If you wanted to capture this change, you'd have to proxy the pushState() method with your own function:

(function (old) {
    window.history.pushState = function () {
        old.apply(window.history, arguments);
        alert(window.location.href);
    }
})(window.history.pushState); 

Read more about the History API at https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history.

like image 169
Andy E Avatar answered Oct 17 '22 10:10

Andy E


Another approach is to hook DOMNodeInserted for the page, and to run when the path matches /messages after insertion:

// ==UserScript==
// ...
// @include https://www.facebook.com/*
// ...
// ==/UserScript==

var url = document.location.toString();
function scriptBody(){
   if (!url.match(/facebook.com\/messages/)) return;
   // ...
   // do stuff
   // ...
});

scriptBody(); // run on initial page load

document.querySelector('html').addEventListener('DOMNodeInserted', function(ev){
  var new_url = document.location.toString();
  if (url == new_url) return; // already checked or processed
  url = new_url;

  scriptBody(); // run when URL changes
});

Note that if you users use the forward/back buttons you may get 'DOMNodeInserted' events for content that is being reinserted to the page that you've already modified with your script, so you'll need to make sure you check whether whatever changes you normally make to the page have already been made, to prevent inserting duplicate controls or whatever.

like image 40
rampion Avatar answered Oct 17 '22 10:10

rampion