< Day Day Up > |
Track what you search for and which search results you follow. Google recently added yet another beta service: My Search History (http://www.google.com/searchhistory/). In a nutshell, you log into your Google account, and My Search History remembers which keywords you search for and which search results you end up following. A nice idea, but it has some limitations that disappointed me when I tried it. My Search History isn't immediately available on the Google home page. Also, clicking a previous search simply reexecutes the search, instead of actually taking me to the result I followed last time. How is that useful? I remember what I searched for; what I want to know is what I found! This hack lets me do what I had hoped the "My Search History" tool would do. 6.12.1. The CodeThis user script runs on all Google pages. The code itself breaks down into three distinct parts:
The end result is seamless: you search, click a search result, and visit the result page. But invisibly, behind the scenes, the user script has tracked and stored your every movement.
Save the following user script as recentsearches.user.js: // ==UserScript== // @name Recent Searches // @namespace http://diveintomark.org/projects/greasemonkey/ // @description remember and display recent Google searches // @include http://www.google.com/* // ==/UserScript== function SavedSearches() { var iCount = GM_getValue('count') || 0; for (var i = 0; i < iCount; i++) { this.push({ "searchtext": GM_getValue('searchtext.' + i, ''), "searchresult": GM_getValue('searchresult.' + i, '')}); } } SavedSearches.prototype = new Array( ); SavedSearches.prototype.find = function(sSearchText) { for (var i = this.length - 1; i >= 0; i--) { if (this[i] == sSearchText) { return i; } } return -1; }; SavedSearches.prototype.append = function(sSearchText) { GM_setValue('searchtext.' + this.length, sSearchText); this.push({"searchtext": sSearchText}); GM_setValue('count', this.length); }; var arSavedSearches = new SavedSearches( ); function getCurrentSearchText( ) { var elmForm = document.forms.namedItem('gs'); if (!elmForm) { return; } var elmSearchBox = elmForm.elements.namedItem('q'); if (!elmSearchBox) { return; } var sKeyword = elmSearchBox.value; if (!sKeyword) { return; } return sKeyword; } function addCurrentSearch( ) { var sCurrentSearchText = getCurrentSearchText( ); if (!sCurrentSearchText) { return; } var sLastSearch = null; if (arSavedSearches.length) { sLastSearch = arSavedSearches[arSavedSearches.length - 1]; } if (sLastSearch && (sLastSearch['searchtext'] == sCurrentSearchText)) { return; } arSavedSearches.append(sCurrentSearchText); } function clearSavedSearches( ) { for (var i = 0; i < arSavedSearches.length; i++) { GM_setValue('searchtext.' + i, ''); GM_setValue('searchresult.' + i, ''); } GM_setValue('count', 0); arSavedSearches = new SavedSearches( ); var elmRecentSearches = document.getElementById('recentsearcheslist'); if (elmRecentSearches) { elmRecentSearches.innerHTML = ''; } } function injectRecentSearches( ) { if (!arSavedSearches.length) { return; } var elmFirst = document.evaluate("//table[@bgcolor='#e5ecf9']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (!elmFirst) { elmFirst = document.evaluate("//form[@name='f']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; } if (!elmFirst) { return; } var htmlRecentSearches = '<p style="font-size: small">Recent searches: '; var iDisplayedCount = 0; for (var i = arSavedSearches.length - 1; (iDisplayedCount <10) && (i >= 0); i--) { var oSearch = arSavedSearches[i]; if (!oSearch['searchresult']) { continue; } var sSearchResult = oSearch['searchresult']; var iSpacePos = sSearchResult.indexOf(' '); var sHref = sSearchResult.substring(0, iSpacePos); var sTitle = sSearchResult.substring(iSpacePos + 1); htmlRecentSearches += '<a href="' + sHref + '" title="' + sTitle + '">' + oSearch['searchtext'] + '</a> · '; iDisplayedCount++; } if (!iDisplayedCount) { return; } htmlRecentSearches += '[<a ' + 'title="Clear saved searches" href="#">clear</a>]</p>'; var elmWrapper = document.createElement('div'); elmWrapper.id = "recentsearcheslist"; elmWrapper.innerHTML = htmlRecentSearches; elmFirst.parentNode.insertBefore(elmWrapper, elmFirst.nextSibling); window.addEventListener('load', function( ) { var elmClearLink = document.getElementById('clearsavedsearches'); elmClearLink.addEventListener('click', clearSavedSearches, true); }, true); } function trackClick(event) { var sHref, sTitle; var elmTarget = event.target; while ((elmTarget.nodeName != 'A') && (elmTarget.nodeName != 'BODY')) { elmTarget = elmTarget.parentNode; } if (elmTarget.nodeName != 'A') { return; } var elmParent = elmTarget.parentNode; while ((elmParent.nodeName != 'P') && (elmParent.nodeName != 'BODY')) { elmParent = elmParent.parentNode; } if (elmParent.nodeName != 'P') { return; } if (elmParent.getAttribute('class') != 'g') { return; } sHref = elmTarget.href; sTitle = elmTarget.textContent; var iSearchIndex = arSavedSearches.find(getCurrentSearchText( )); if (iSearchIndex == -1) { addCurrentSearch( ); iSearchIndex = arSavedSearches.length - 1; } GM_setValue('searchresult.' + iSearchIndex, sHref + ' ' + sTitle); } if (/^\/search/.test(location.pathname)) { injectRecentSearches( ); addCurrentSearch( ); document.addEventListener('click', trackClick, true); } else if (/^\/$/.test(location.pathname)) { injectRecentSearches( ); } 6.12.2. Running the HackAfter installing the user script (Tools Figure 6-19. Recent searches on the Google home page![]() You will also see the list of recent searches on the search results page itself. Hovering over a recent search displays the title of the linked page, as shown in Figure 6-20. Figure 6-20. Recent searches on Google's search results page![]() 6.12.3. Hacking the HackThe links in the recent searches list go directly to the search result you clicked when you searched. But what if you want to rerun the search and go somewhere else? That's easy enough. In the injectRecentSearches function, find these two lines: var sHref = sSearchResult.substring(0, iSpacePos); var sTitle = sSearchResult.substring(iSpacePos + 1); And change them like this: var sHref = 'http://www.google.com/search?q=' + escape(sSearchResult); var sTitle = 'previously found ' + sSearchResult.substring(iSpacePos + 1) + '\n' + sSearchResult.substring(0, iSpacePos); Now, if you hover over a link in the recent searches list, the tool tip will display the title and URL of the page you went to last time. If you click the link, it will reexecute the search so that you can choose a different search result this time. |
< Day Day Up > |