How can I use Javascript to automatically print search results from a series of HTTP search queries?

865 views Asked by At

I have a tampermonkey script where I'm trying to take an array of names, and for each one perform a search and print the page. It runs automatically when you load the page, which is why the if statement is necessary.

$(document).ready(function(){
    var searchBar = $('input[name="searchfield"]');
    var submit = $('button[name="searchbyname"]');

    if ( searchBar.val() < 1 ) {
        var namesArray = prompt('enter names to search, separated by commas').split(', ');
        $.each(namesArray, function(i, v) {
            $(searchBar).val(v);
            $(submit).trigger('click');
            window.print();
        });

    } 
})

My problem is that it is only running the $(submit).trigger('click'); on the last loop through. So if my array is 'one, two, three' it will enter 'one' into the search bar, replace it with 'two,' then 'three,' and only then will it actually trigger the search button.

2

There are 2 answers

0
Ben Brock On BEST ANSWER

(This answer is in response to what I perceive as the real need, "How can I use Javascript to automatically print search results from a series of HTTP search queries?", in good faith that the poster will tweak the question accordingly.)

You are actually trying to use Javascript to print search results from different pages. Your approach will not work for this purpose (and therefore the original question of $.each looping is invalid); every time the search is submitted, your Javascript runtime and userscripts are nuked.

To accomplish the end goal, you need to separate the query loop from the window that submits the HTTP request. The trick: create an iframe containing this website, then control that iframe from the top window.

Here's code that could be copied into the developer console directly. I've only tested it with the console, but it should be adaptable for script injectors like Tampermonkey.

(function(){
    // Define the bits that work with this particular website.
    var fieldname = 'searchfield';
    var formname  = 'ECPCIS_list';

    // Figure out which names need to be searched.
    var query_iter = 0
        , queries = prompt('What names do you want to search for?').split(',').filter(function (val) {
            return val.trim();
        });
    if (!queries.length) { return; }

    // Store the current URL.
    var url = window.location.href;

    // Reopen the current document (in the context of the current domain security), and replace the
    // document contents with a single iframe. The iframe source is equal to the original URL.
    document.open();
    document.close();
    var iframe = document.createElement('IFRAME');

    // Make sure that the styles are set up in such a way that the iframe gets full height.
    // We'll add a listener that resizes the `top` window (our script) whenever the iframe loads.
    document.body.setAttribute('style', "width:100%;height:100%;margin:0;");
    iframe.setAttribute('style', "width:100%;height:100%;");
    iframe.setAttribute('scrolling', 'no');

    // Create a method to handle the query/repeat lifecycle.
    var runQuery = function() {
        document.body.style.height = iframe.contentWindow.getComputedStyle(iframe.contentDocument.body).getPropertyValue('height');

        // Find the search box. If it doesn't exist yet, continue to wait.
        var fields = iframe.contentDocument.getElementsByName(fieldname);
        if (fields.length == 0) {
            setTimeout(100, runQuery);
            return;
        }

        // If this isn't the first iteration, we need to wait to print the screen.
        if (query_iter > 0) {
            window.print();

            if (query_iter >= queries.length) { return; }
        }

        // Set the query in the search box.
        fields[0].value = queries[query_iter];

        // Increment the query iteration.
        query_iter += 1;

        // Submit the form. This will refresh the iframe.
        // When it is done loading, runQuery will be executed again.
        iframe.contentDocument.getElementsByName(formname)[0].submit();
    }
    iframe.addEventListener('load', runQuery);

    // Stick the iframe into the DOM and load the original page.
    // Now it looks like we're in the same page we were just on; the fact that there are two layers
    // is visually hidden. IOW, the "window.print" method will capture the right output.
    document.body.appendChild(iframe);
    iframe.src = url;
})()

Note that the parts designed specifically for your use case are fieldname and formname at the top. The rest of this is completely generic; you could use with any website that has appropriate name attributes on the input and form elements.

2
Ben Brock On

Is the submit handled via AJAX?

  • Yes, it's an AJAX form: you need to wait for the server to respond and the DOM to update before you take a screenshot.
  • No, it's a normal POST form: your Javascript runtime will disappear when the document is replaced with the next HTTP request.
  • No, it's an inline javascript search within the DOM: still a good idea to use a promise or other deferral strategy to be sure that everything has updated before you print.

Either way, I'd suggest an onclick handler on the button to help you debug further. I bet it is being fired, but you're continuing with operations rather than deferring until the response has loaded.

Each new request clobbers the last, so even though all of them trigger, you only see the last one take effect.