w3schools scrollrestoration replacestate mdn example ejemplo javascript ajax dom google-chrome-extension vk

javascript - scrollrestoration - insertar script de contenido cuando la página fue modificada por history.pushState y ajax call



window.history clear (1)

Hay dos formas posibles en que puedo pensar:

1 - Use temporizadores para verificar si su script todavía está allí, si no, agregue nuevamente ...
2 - Compruebe si hay llamadas ajax y si su url coincide con una de las URL que eliminan su secuencia de comandos, agregue nuevamente la secuencia de comandos.

Su secuencia de comandos (la definida en el manifiesto) todavía está allí, incluso después de las llamadas ajax, simplemente no se ejecuta de nuevo (no estoy seguro de lo que sucede con el empujador de historial). Entonces, asumo que necesitas leer algunos elementos o volver a ejecutar el stript. Supuse que agregaste el script que agrega una etiqueta html.

Entonces, lo que necesita es algo para leer elementos o volver a ejecutar un determinado código.

1 - Enfoque de temporizador: Creé una solución para cualquier elemento (no solo scripts) que desee agregar a un determinado elemento de destino en una página.

Utiliza un temporizador para verificar si el elemento objetivo está presente. Cuando encuentra el elemento objetivo, agrega el mío. Luego, el temporizador se ajusta para verificar si mi elemento aún está allí. Si no, agregue nuevamente.

Solo necesita llamar a appendChildPersistent una sola vez y esto se mantendrá activo todo el tiempo que navegue.

var timers = {}; //stores the setInterval ids //this is the only method you need to call //give your script an `id` (1) //the child is your script, it can be anything JQuery.append can take //toElem is the Jquery "SELECTOR" of the element to add your script into. //I''m not sure what would happen if toElem were not a string. //callback is a function to call after insertion if desired, optional. appendChildPersistent = function(id, child, toElem, callback) { //wait for target element to appear withLateElement(toElem, function(target) { target.append(child); //appends the element - your script if (typeof callback !== ''undefined'') callback(); //execute callback if any //create a timer to constantly check if your script is still there timers[id] = setInterval(function() { //if your script is not found, clear this timer and tries to add again if (document.getElementById(id) === null) { clearInterval(timers[id]); delete timers[id]; appendChildPersistent(id, child, toElem, callback); } },3000); }); } //this function waits for an element to appear on the page //since you can''t foresee when an ajax call will finish //selector is the jquery selector of the target element //doAction is what to do when the element is found function withLateElement(selector, doAction) { //checks to see if this element is already being waited for if (!(selector in timers)) { //create a timer to check if the target element appeared timers[selector] = setInterval(function(){ var elem = $(selector); //checks if the element exists and is not undefined if (elem.length >= 0) { if (typeof elem[0] !== ''undefined'') { //stops searching for it and executes the action specified clearInterval(timers[selector]); delete timers[selector]; doAction(elem); } } }, 2000); } }

(1) Parece que no es un problema agregar una Id a una etiqueta de script: otorgar una ID a la etiqueta del script

2 - Capture las llamadas ajax

Una opción es usar chrome.webRequest . Pero, curiosamente, esto no funcionó para mí. Otra opción está abajo.

Para este caso, verifique esta respuesta y no olvide leer la respuesta relacionada a la extensión de Chrome allí. Solo funcionará si sigues todo el procedimiento. Afortunadamente, lo probé hoy y funciona muy bien: p

Aquí, lo que debes hacer es cambiar los métodos XMLHttpRequest open y send para detectar (y posiblemente también obtener los parámetros) cuando son llamados.

En Google Extension, sin embargo, es absolutamente necesario que inyecte el stript en la página (no una página de fondo o script que inyecte su script de contenido, sino su script de contenido inyectando algún código en el dom , como el siguiente).

var script = document.createElement(''script''); script.textContent = actualCode; //actual code is the code you want to inject, the one that replaces the ajax methods document.head.appendChild(script); //make sure document.head is already loaded before doing it script.parentNode.removeChild(script); //I''m not sure why the original answer linked removes the script after that, but I kept doing it in my solution

Esto es crucial porque la extensión intenta crear un entorno aislado, y los cambios que haga a XMLHttpRequest en este entorno simplemente no tomarán parte. (Es por eso que JQuery.ajaxComplete no parece funcionar, necesita inyectar un script en la página para que funcione, mire aquí )

En esta solución pura de javascript , reemplazas los métodos:

//enclosing the function in parentheses to avoid conflict with vars from the page scope (function() { var XHR = XMLHttpRequest.prototype; // Store the orignal methods from the request var open = XHR.open; var send = XHR.send; // Create your own methods to replace those //this custom open stores the method requested (get or post) and the url of the request XHR.open = function(method, url) { this._method = method; //this field was invented here this._url = url; //this field was invented here return open.apply(this, arguments); //calls the original method without any change //what I did here was only to capture the method and the url information }; //this custom send adds an event listener that fires whenever a request is complete/loaded XHR.send = function(postData) { //add event listener that fires when request loads this.addEventListener(''load'', function() { //what you want to do when a request is finished //check if your element is there and readd it if necessary //if you know the exact request url, you can put an if here, but it''s not necessary addMyElementsToPage(); //your custom function to add elements console.log("The method called in this request was: " + this._method); console.log("The url of this request was: " + this._url); console.log("The data retrieved is: " + this.responseText); }); //call the original send method without any change //so the page can continue it''s execution return send.apply(this, arguments); //what we did here was to insert an interceptor of the success of a request and let the request continue normally }; })();

Me enfrenté al problema de insertar script de contenido en la página que fue modificado por history.pushState y ajax call. Encontré un tema similar en stackoverflow, pero esa solución no funciona para mí (esa solución estaba en el uso de chrome.webNavigation.onHistoryStateUpdated y del evento "popstate").

Aquí hay un fragmento de mi manifiesto:

"content_scripts": [ { "matches": ["https://vk.com/audios*", "https://vk.com/al_audio.php*"], "js": ["jquery-2.1.4.min.js", "getListOfSongs.js"] } ]

chrome.webNavigation.onHistoryStateUpdated funciona solo si navego a la otra página, si navego a la misma página muchas veces en secuencia, no ocurre nada. Por ejemplo: funciona cuando

1) Vaya a https://vk.com/audios * - página de apertura primera vez o recarga

2) Vaya a la https://vk.com/some_other_page - llamada ajax

3) Ir a la https://vk.com/audios * - llamada ajax

No funciona cuando

1) Vaya a https://vk.com/audios * - página de apertura primera vez o recarga

2) Nuevamente vaya a la https://vk.com/audios * - llamada ajax, en este punto el script de contenido no se está inyectando
3) Nuevamente vaya a la https://vk.com/audios * - llamada ajax, en este punto el script de contenido no se está inyectando y así sucesivamente

Cada vez que hago clic en la misma página por segunda vez, la siguiente solicitud genera:

https://vk.com/al_audio.php?__query=audios ********* & _ ref = left_nav & _smt = audio% 3A2 & al = -1 & al_id = ******** & _ rndVer = 60742

(los parámetros de la solicitud pueden variar)

Además JQuery .ajaxComplete no detecta ningún evento en este caso.

Y pushState no activa el evento "popstate", por lo que no puedo usar el evento window.onpopstate

Podría usar chrome.webNavigation.onDOMContentLoaded y chrome.webNavigation.onCompleted, pero cuando vuelvo a cargar la página, estos eventos ocurren más de una vez, por lo que el script se inyectará más de una vez.

¿Cuál es la mejor solución para este caso?