开发者

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

开发者 https://www.devze.com 2023-04-04 08:00 出处:网络
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.

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/*
// ==/User开发者_开发问答Script==

alert(location.href);

How can I correctly detect page changes?


Firefox version: 6.0.2

Greasemonkey version: 0.9.11


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.


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.


+1 to @rampion suggestions. I wanted to perform a simple redirect though and looking for elements on page was not very useful as I don't want to redirect user unattendedly.

Anyway, I used this code to install a listener that would redirect where needed upon user clicking on a link with particular href:

if (document.addEventListener ){
  document.addEventListener("click", function(event) {
    var targetElement = event.target || event.srcElement;
    // TODO: support deeper search for parent element with a href attribute
    var href = targetElement.getAttribute('href') || targetElement.parentElement.getAttribute('href') ;
    if (href && videoURLRe.test(href)) {
      var target = "";
      if (href.indexOf("/") == 0) {
        target = "https://m.facebook.com" + href
      } else {
        target = href.replace("www.facebook", "m.facebook");
      }
      window.location.assign(target);
    }   
  }, true);
}

Works pretty neat. I had to figure correct third addEventListener param so that my listener is executed before any others.

For full script look at https://greasyfork.org/en/scripts/8176-switch-to-mobile-version-on-facebook-video-page

I couldn't find any way to reliably detect URL changes regardless of method used by the web site to change that URL. @andy-e approach seems awesome but didn't work for me for some reason. Perhaps I couldn't make script @grant tag properly.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号