Защо greasemonkey не открива някои промени в страницата във facebook?

Опитвах се да направя user.js към /messages страница във facebook, но изглежда, че greasemonkey не забелязва, когато навигацията се промени от / към /messages. Среща се и в други вътрешни страници. Първо си помислих, че е причинено от AJAX навигация, но URL адресът се променя (не хеш част), така че това е нормална навигация, нали?

Това е тестова страница, която използвах:

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

alert(location.href);

Как мога да открия правилно промените в страницата?


Версия на Firefox: 6.0.2

Greasemonkey версия: 0.9.11


person Ravan Scafi    schedule 11.09.2011    source източник
comment
Този друг въпрос може да е от значение. stackoverflow.com/questions/3522090/   -  person bronsoja    schedule 12.09.2011


Отговори (3)


За браузъри, които го поддържат, включително Firefox 4+, Facebook се възползва от HTML5 History API. Този API позволява местоположението да се променя с помощта на метода history.pushState(), въпреки че всъщност не се извършва навигация. Въпреки че може да изглежда, че страницата се е променила, всичко, което се е случило, е задкулисно извикване на ajax, което променя по-голямата част от съдържанието.

Ако искате да заснемете тази промяна, ще трябва да проксиирате метода pushState() с ваша собствена функция:

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

Прочетете повече за API за история на https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history.

person Andy E    schedule 11.09.2011
comment
Не мисля, че трябва да използвате прокси - не можахте ли просто да обработите събитието window.onpopstate? - person Coderer; 08.01.2014
comment
onpopstate не открива кога се извиква pushState за нови страници, само когато използвате бутоните за напред или назад (или извиквания на API за напред и назад). - person rampion; 08.01.2014
comment
проблемът с този подход е, че новите елементи на страницата не са непременно заредени след връщане на old.apply(window.history, arguments), така че може да не е готов за обработка на вашия скрипт. - person rampion; 08.01.2014
comment
@andy-e по някаква причина това не работи с потребителски скриптове за мен - функцията не е мутирана. Възможно ли е Twitter да запазва копие на оригиналния обект в закриване? В момента използвам това заобиколно решение, но е неоптимално, тъй като се изпълнява твърде много пъти github.com/giuseppeg/refined-twitter-lite/blob/ - person G.G.; 27.01.2019

Друг подход е да закачите DOMNodeInserted за страницата и да стартирате, когато пътят съвпада с /messages след вмъкване:

// ==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
});

Обърнете внимание, че ако потребителите използват бутоните напред/назад, може да получите събития „DOMNodeInserted“ за съдържание, което се вмъква отново в страницата, която вече сте модифицирали с вашия скрипт, така че ще трябва да проверите дали каквито и да било промени които обикновено правите на страницата, вече са направени, за да предотвратите вмъкването на дублиращи се контроли или каквото и да било.

person rampion    schedule 08.01.2014

+1 към @rampion предложения. Исках обаче да извърша просто пренасочване и търсенето на елементи на страницата не беше много полезно, тъй като не искам да пренасочвам потребителя без надзор.

Както и да е, използвах този код, за да инсталирам слушател, който ще пренасочи където е необходимо, когато потребителят кликне върху връзка с конкретен 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);
}

Работи доста спретнато. Трябваше да разбера правилния трети параметър addEventListener, така че моят слушател да се изпълни преди всеки друг.

За пълния скрипт вижте https://greasyfork.org/en/scripts/8176-switch-to-mobile-version-on-facebook-video-page

Не можах да намеря начин за надеждно откриване на промени в URL адреса, независимо от метода, използван от уеб сайта за промяна на този URL адрес. @andy-e подходът изглежда страхотен, но не работи за мен по някаква причина. Може би не можах да направя правилно таг на скрипта @grant.

person akostadinov    schedule 21.04.2015