GollyJer
GollyJer

Reputation: 26672

Why does waitForKeyElements need another timeout for Google search results?

The following script does what I want it to do but not as fast as I'd like it to do it. :-)

The goal is always show the search tools that become visible when the Search Tools button is clicked on Google Search results.

I can't get waitForKeyElements to work without applying a timer.
WaitForKeyElements was made for this purpose so I feel like I'm missing something.

This script works, sort of, but takes too long and seems brittle:

// ==UserScript==
// @name        GollyJer's Expand Google Search Tools
// @namespace   gollyjer.com
// @version     1.0
// @include      /^https?\:\/\/(www|news|maps|docs|cse|encrypted)\.google\./
// @require     http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant       GM_addStyle
// ==/UserScript==

function expandSearchTools () {
    // Fires too soon?
    // var searchToolsButton = document.getElementById("hdtb-tls");   
    // searchToolsButton.click();

    // Working but distracting.
    setTimeout(
        function(){
          var searchToolsButton = document.getElementById("hdtb-tls");   
          searchToolsButton.click();

    }, 1000);
}

waitForKeyElements ("#ires", expandSearchTools);

Upvotes: 3

Views: 765

Answers (2)

Brock Adams
Brock Adams

Reputation: 93473

Sometimes it's not enough to wait for a particular element, to click it. Sometimes you must also allow the javascript associated with that element to initialize.

This can be difficult on pages like Google's, where the javascript is very involved and not (easily) human readable.

A general way around this, when clicking nodes is to check for the expected effect of the click, and repeat the click until that happens.

In this case, the click is supposed to open the Search tools bar. So we can check to see if that happens and keep clicking until the page's click event handler is ready and responds.

This also adds a timer, but it is faster and more flexible than the one-shot delay in the question.
It also has the advantage that, since we use the page's expected inputs to change things, the page's javascript won't get out of sync with the page or enter an unexpected state (crash, in the worst case).

Checking for the expected effect works in the general case, when a simple click is not working:

// ==UserScript==
// @name        GollyJer's Expand Google Search Tools
// @include      /^https?\:\/\/(www|news|maps|docs|cse|encrypted)\.google\./
// @require     http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant       GM_addStyle
// ==/UserScript==

waitForKeyElements ("#hdtb-tls", clickNodeTilItSticks);

function clickNodeTilItSticks (jNode) {
    var srchToolBar = $("#hdtbMenus")[0];
    var sanityCount = 1;
    var menusVisiblePoller = setInterval ( function () {
            if (sanityCount < 20  &&  srchToolBar.offsetWidth === 0  &&  srchToolBar.offsetHeight === 0) {
                var clickEvent  = document.createEvent ('MouseEvents');
                clickEvent.initEvent ('click', true, true);
                jNode[0].dispatchEvent (clickEvent);
            }
            else {
                clearInterval (menusVisiblePoller);
            }
            sanityCount++;
        },
        88
    );
}

Upvotes: 2

GollyJer
GollyJer

Reputation: 26672

OK, figured out a slightly different path with much more reliable results...

Clicking the Search Tools button does a few things in the DOM, but the most important for this issue is replacing one of the classes on #hdtbMenus which causes the search tools to show instead of the result count.

Simply changing this class myself has proven much more reliable.
This code now works great.

// ==UserScript==
// @name        GollyJer's Expand Google Search Tools
// @namespace   gollyjer.com
// @version     1.0
// @include      /^https?\:\/\/(www|news|maps|docs|cse|encrypted)\.google\./
// @require     http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant       GM_addStyle
// ==/UserScript==

// Hide the Search Tools button.
GM_addStyle("#hdtb-tls { display: none !important; }");

// Remove the menu animation for "instant" change to the menu.
GM_addStyle("#hdtbMenus { transition: none !important; }");

// Show the Search Tools menu.
waitForKeyElements ("#hdtbMenus", expandSearchTools);
function expandSearchTools (jNode) {
    jNode.removeClass("hdtb-td-c hdtb-td-h").addClass("hdtb-td-o");
}

Upvotes: 1

Related Questions