PowerLove PowerLove - 3 months ago 16
Ajax Question

chrome extension run script after ajax

I am new to Javascript, and I am creating a chrome extension where I am trying to inject some HTMLs into the existing public website,

My current code is something like this,

if (document.readyState ==='complete'){
inject_html();
}


However, on the current website, when a button is pressed, ajax is processed and new HTML DOM is loaded for the same url, so the script doesn't run.

Is there a way to listen to whenever ajax is finished processing? What is the best way in this case, can an expert help me?

Answer

This is rather hacky, but you can override any property (and thus interpose any method call) of the XMLHttpRequest prototype, as well as the function/constructor itself.
The most convenient thing to do in your case is probably to hook the XMLHttpRequest function itself, and simply add an event listener there:

var originalXHR = XMLHttpRequest;
XMLHttpRequest = function()
{
    var ret = new originalXHR();
    ret.addEventListener('load', function()
    {
        console.log('Ajax request finished!');
    });
    return ret;
};

The control flow here goes like this:

  • Call original function
  • Modify return value
  • Return modified value

This takes advantage of the fact that if in JavaScript a constructor returns a value, that value replaces the object created with new.

In action:

// Interface code
var field = document.querySelector('input');
document.querySelector('button').addEventListener('click', function()
{
    var xhr = new XMLHttpRequest();
    // crossorigin.me because we need a CORS proxy for most external URLs
    xhr.open("GET", 'https://crossorigin.me/' + field.value);
    xhr.send(null);
});

// Hooking code
var originalXHR = XMLHttpRequest;
XMLHttpRequest = function()
{
    var ret = new originalXHR();
    ret.addEventListener('load', function(ev)
    {
        // var xhr = ev.target;
        console.log('Ajax request finished!');
    });
    return ret;
};
<!-- Demo page: -->
URL: <input type="text" value="https://google.com"><br>
<button>Load via XHR</button>

Note that this only gives you a method to detect when an XHR has finished loading, and not control over its return value. From within the function that does console.log, you do however have access to the XHR itself, via ev.target.

You could also create hooking points to modify the loaded content before it reaches the code on the page, but that would require a couple more hooks, because listeners can be added in more than one way (.onload, .onreadystatechange, .addEventListener, etc), but it would be doable if necessary.