3

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);
Community
  • 1
  • 1
GollyJer
  • 23,857
  • 16
  • 106
  • 174

2 Answers2

2

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
    );
}
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • OK, I have to ask... why 88? – GollyJer Nov 13 '15 at 14:31
  • By the way... Thanks! This works perfectly and answers the question directly. – GollyJer Nov 13 '15 at 14:32
  • You're welcome! As for 88, I only did a few sanity checks on that value. It *should* work in all cases, but I did not test it rigorously. Still, many people consider the number 8 to be lucky and 88 as well. :) – Brock Adams Nov 13 '15 at 18:23
  • 1
    Brock. Not sure if you'll see my github comment so posting here as well. https://gist.github.com/BrockA/2625891 – GollyJer Nov 17 '15 at 17:54
  • Thanks. Still not getting Gist emails, though the ones from main GitHub come through just fine. Anyway, I replied at gist.github.com. Use whatever works for you. – Brock Adams Nov 17 '15 at 20:07
1

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");
}
GollyJer
  • 23,857
  • 16
  • 106
  • 174
  • Your answer is probably fine in this particular Google case. But this approach won't always work, generally, because the JS's internal state might track those classes and assume that they are unchanged (causing unexpected behavior). Or, the click might create elements and/or other code -- rather than merely unhiding some nodes. – Brock Adams Nov 13 '15 at 05:46
  • Good point. The click event definitely wasn't reliable though. Glad to have found the workaround in this case. – GollyJer Nov 13 '15 at 06:02