I've faced with the problem with inserting content script into the page which was changed by history.pushState and ajax call. I've found the similar topic at stackoverflow, but that solution doesn't work for me (that solution was in using of chrome.webNavigation.onHistoryStateUpdated and "popstate" event ).
Here is a fragment of my manifest:
"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 works only if i navigate to the another page, if i navigate to the same page many times in sequence nothing happens. For example: it works when
1) Go to the https://vk.com/audios* - opening page first time or reloading
2) Go to the https://vk.com/some_other_page - ajax call
3) Go to the https://vk.com/audios* - ajax call
It doesn't work when
1) Go to the https://vk.com/audios* - opening page first time or reloading
2) Again go to the https://vk.com/audios* - ajax call, at this point content script isn't injecting
3) Again go to the https://vk.com/audios* - ajax call, at this point content script isn't injecting and so on
Every time i am clicking to the same page for the second time and so on the following request is generating:
https://vk.com/al_audio.php?__query=audios*********&_ref=left_nav&_smt=audio%3A2&al=-1&al_id=********&_rndVer=60742
(parameters of request may vary)
Also JQuery .ajaxComplete doesn't catch any events in this case.
And pushState doesn't fire "popstate" event, so i can't use window.onpopstate event
I might use chrome.webNavigation.onDOMContentLoaded and chrome.webNavigation.onCompleted but when i reload page these events are happening more then one time, so script will be injected more than one time.
What is the best solution for this case?
There are two possible ways I can think of:
1 - Use timers to check if your script is still there, if not, add again...
2 - Check for ajax calls and if their url matches one of the urls that remove your script, add the script again.
Your script (the one defined in manifest) is still there, even after the ajax calls, it just doesn't run again (not sure what happens with the history pusher). So, I'm assuming you need to just readd some elements or rerun the stript. I supposed you adding the script appending an html tag.
So what you need is something to readd elements or rerun a certain code.
1 - Timer approach - I created a solution for any element (not only scripts) that I wish to add to a certain target element in a page.
It uses a timer to check if the target element is present. When it finds the target element, it adds mine. Then the timer is adjusted to check if my element is still there. If not, add again.
You just need to call
appendChildPersistent
a single time and this will keep active all the time you navigate around.(1) It seems it's not a problem to add an Id to a script tag: Giving the script tag an ID
2 - Capture the ajax calls
An option is to use chrome.webRequest. But strangely, this didn't work for me. Another option is below.
For this case, check this answer, and don't forget to read the related answer to Chrome extension in there. It will only work if you follow the entire procedure. Fortunately, I tested it today and it works great :p
Here, what you do is to change the
XMLHttpRequest
methodsopen
andsend
to detect (and possibly get the parameters too) when they are called.In the Google Extension, however, it's absolutely necessary that you inject the stript in the page (not a background page or script injecting your content script, but your content script injecting some code into the dom, like the following).
This is crucial because the extension tries to create an isolated environment, and the changes you do to the
XMLHttpRequest
in this environment will simply not take part. (That's why JQuery.ajaxComplete doesn't seem to work, you need to inject a script in the page for it to work - look here)In this pure javascript solution, you replace the methods: