Reputation: 26672
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
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
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