2011-09-11 2 views
5

Estaba tratando de hacer una página user.js a/messages en Facebook, pero parece que greasemonkey no se da cuenta cuando la navegación cambia de/a/messages. También ocurre en otras páginas internas. Primero pensé que fue causado por la navegación AJAX, pero la URL cambia (no parte hash), por lo que es la navegación normal, ¿verdad?¿Por qué greasemonkey no detecta algunos cambios de página en Facebook?

Ésta es una página de prueba que he utilizado:

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

alert(location.href); 

¿Cómo puedo detectar correctamente los cambios de página?


Firefox versión: 6.0.2

versión de Greasemonkey: 0.9.11

+0

Esta otra pregunta puede ser relevante. http://stackoverflow.com/questions/3522090/event-when-window-location-href-changes – bronsoja

Respuesta

8

Para los navegadores que lo soportan, incluyendo Firefox 4+, Facebook se aprovecha de la API de HTML5 Historia. Esta API permite cambiar la ubicación utilizando el método history.pushState(), aunque en realidad no se navega. Aunque la página parece haber cambiado, todo lo que sucedió es una llamada ajax detrás de escena que cambia la mayor parte del contenido.

Si quiere capturar este cambio, tendríamos que el método de proxy pushState() con su propia función:

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

Más información acerca de la API de Historia en https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history.

+0

No creo que tengas que usar un proxy, ¿no podrías manejar el evento 'window.onpopstate' ? – Coderer

+0

'onpopstate' no detecta cuando se invoca pushState para las páginas nuevas, solo cuando se usan los botones hacia adelante o hacia atrás (o hacia adelante y hacia atrás llamadas API). – rampion

+0

el problema con este enfoque es que los nuevos elementos de la página no se han cargado necesariamente después de que 'old.apply (window.history, arguments)' devuelve, por lo que puede no estar listo para su secuencia de comandos para procesar. – rampion

3

Otro enfoque es conectar DOMNodeInserted para la página, y para funcionar cuando la ruta de acceso coincide /messages después de la inserción:

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

en cuenta que si los usuarios utilizan los botones de avance/atrás puede recibir eventos 'DOMNodeInserted' para el contenido que se reinserte en la página que ya ha modificado con su secuencia de comandos, por lo que deberá asegurarse de comprobar si los cambios que realiza normalmente en la página ya se han realizado, para evitar insertar controles duplicados o lo que sea .

0

+1 a @rampion sugerencias. Sin embargo, quería realizar un redireccionamiento simple y no era muy útil buscar elementos en la página, ya que no quiero redirigir al usuario desatendidamente.

De todos modos, he utilizado el código para instalar un oyente que redirigir cuando sea necesario al usuario haga clic en un enlace con especial 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); 
} 

funciona bastante bien cuidado. Tuve que calcular el tercer parámetro addEventListener correcto para que mi oyente se ejecute antes que cualquier otro.

Para mirada llena secuencia de comandos en https://greasyfork.org/en/scripts/8176-switch-to-mobile-version-on-facebook-video-page

no pude encontrar ninguna manera de detectar de forma fiable URL cambia, independientemente del método utilizado por el sitio web para cambiar esa URL. El enfoque de @andy-e parece increíble, pero no funcionó para mí por alguna razón. Tal vez no pude hacer la secuencia de comandos @grant correctamente.

Cuestiones relacionadas