Google Code Search Autocomplete

By Jim Wilson Last update Oct 13, 2006 — Installed 1,022 times.
// Google Code Search Autocomplete
// version 0.1
// 2006-10-12
// Copyright (c) 2006, Jim R. Wilson (wilson.jim.r at gmail)
// Released under The MIT License (http://www.opensource.org/licenses/mit-license.php)
//
// Purpose:
//    This userscript adds an autocomplete drop-down to Google's Code Search
//
// Example:
//     To see an example of this script in action, visit the Google's Code Search:
//        http://www.google.com/codesearch
//     Just start typing in the search box to see the drop-down list of suggestions.
//     Please note that not all queries will return results.
//
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Then restart Firefox and revisit this script.
// Under Tools, there will be a new menu item to "Install User Script".
// Accept the default configuration and install.
//
// To uninstall, go to Tools/Manage User Scripts,
// select "Google Code Search Autocomplete", and click Uninstall.
//
// --------------------------------------------------------------------
// Copyright (c) 2006 Jim R. Wilson
// 
// Permission is hereby granted, free of charge, to any person 
// obtaining a copy of this software and associated documentation 
// files (the "Software"), to deal in the Software without 
// restriction, including without limitation the rights to use, 
// copy, modify, merge, publish, distribute, sublicense, and/or 
// sell copies of the Software, and to permit persons to whom the 
// Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be 
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
// OTHER DEALINGS IN THE SOFTWARE.
// --------------------------------------------------------------------
//
// ==UserScript==
// @name          Google Code Search Autocomplete
// @namespace     http://jimbojw.blogspot.com/
// @description   Adds autocomplete functionality to fields in Google Code Searches.
// @include       http://www.google.com/codesearch*
// @exclude       http://www.google.com/codesearch/advanced_code_search*
// ==/UserScript==

// Anonymous wrapper function
(function() {

/**
 * Inject Prototype and Scriptaculous dependencies.
 */
var scripts = [
    'http://wiki.script.aculo.us/javascripts/prototype.js',
    'http://wiki.script.aculo.us/javascripts/effects.js',
    'http://wiki.script.aculo.us/javascripts/controls.js'
];
for (var i=0; i<scripts.length; i++) {
    var script = document.createElement('script');
    script.src = scripts[i];
    document.getElementsByTagName('head')[0].appendChild(script);
}

/**
 * Inject the GCSAutocompleter.
 * Note: This has to be injected straight into the page to previously included libraries.
 */
var scriptText = 
    'window["sf"] = function(){};' + "\n" +
    'GCSAutocompleter = Class.create();' + "\n" +
    'Object.extend(Object.extend(GCSAutocompleter.prototype, Ajax.Autocompleter.prototype), {' + "\n" +
    '  getUpdatedChoices: function() {' + "\n" +
    '    entry = encodeURIComponent(this.options.paramName) + "=" + ' + "\n" +
    '      encodeURIComponent(this.getToken()+"\\\\w*");' + "\n" +
    '     this.options.parameters = this.options.callback ?' + "\n" +
    '      this.options.callback(this.element, entry) : entry;' + "\n" +
    '     if(this.options.defaultParams) ' + "\n" +
    '      this.options.parameters += "&" + this.options.defaultParams;' + "\n" +
    '     new Ajax.Request(this.url, this.options);' + "\n" +
    '  },' + "\n" +
    '  onComplete: function(request) {' + "\n" +
    '    if (request.responseText.length > 500000) return;' + "\n" +
    '    var doc = document.createElement("div");' + "\n" +
    '    var text = request.responseText;' + "\n" +
    '    text = text.replace(new RegExp(\'[\\\\s\\\\S]*<body\',"im"),"<body");' + "\n" +
    '    text = text.replace(new RegExp(\'</body>[\\\\s\\\\S]*\',"im"),"</body>");' + "\n" +
    '    doc.innerHTML = text;' + "\n" +
    '    var bs = doc.getElementsByTagName("b");' + "\n" +
    '    var list = new Array();' + "\n" +
    '    var lim = (this.options.limit ? this.options.limit : bs.length);' + "\n" +
    '    var wordRE = new RegExp(this.getToken(),"i");' + "\n" +
    '    for (var i = j = 0; i<bs.length && j<lim; i++) {' + "\n" +
    '        if (bs[i].className!="hl") continue;' + "\n" +
    '        var b = bs[i].innerHTML;' + "\n" +
    '        if (!list.include(b) && wordRE.test(b)) {' + "\n" +
    '            list.push(b);' + "\n" +
    '            j++;' + "\n" +
    '        }' + "\n" +
    '    }' + "\n" +
    '    list = list.sort( function (x,y) {' + "\n" +
    '        var a = String(x).toUpperCase(); ' + "\n" +
    '        var b = String(y).toUpperCase(); ' + "\n" +
    '        if (a > b) return 1 ' + "\n" +
    '        if (a < b) return -1 ' + "\n" +
    '        return 0;' + "\n" +
    '    });' + "\n" +
    '    if (!list.length) return;' + "\n" +
    '    var tokenRE = new RegExp("("+this.getToken()+")","i");' + "\n" +
    '    list = list.invoke( "replace", tokenRE, "<b>$1</b>" );' + "\n" +
    '    list = list.join("</li><li style=\'height:1.15em;\'>");' + "\n" +
    '    list = "<ul><li style=\'height:1.15em;\'>" + list + "</li></ul>";' + "\n" +
    '    this.updateChoices(list);' + "\n" +
    '  }' + "\n" +
    '});';
var script = document.createElement('script');
script.appendChild(document.createTextNode(scriptText));
document.getElementsByTagName('head')[0].appendChild(script);

/**
 * Inject the GCS Autocompleter style.
 */
var styleText = 
    'div.autocomplete {' + "\n" +
    '  background-color:#fff;' + "\n" +
    '  border:1px solid #888;' + "\n" +
    '  margin:0px;' + "\n" +
    '  padding:0px;' + "\n" +
    '}' + "\n" +
    'div.autocomplete ul {' + "\n" +
    '  list-style-type:none;' + "\n" +
    '  margin:0px;' + "\n" +
    '  padding:0px;' + "\n" +
    '}' + "\n" +
    'div.autocomplete ul li.selected {' + "\n" +
    '  background-color:#3366cc;' + "\n" +
    '  color:#fff;' + "\n" +
    '}' + "\n" +
    'div.autocomplete ul li {' + "\n" +
    '  list-style-type:none;' + "\n" +
    '  display:block;' + "\n" +
    '  margin:0;' + "\n" +
    '  padding:0 0 0.25em 0.25em;' + "\n" +
    '  cursor:pointer;' + "\n" +
    '  text-align:left;' + "\n" +
    '  font-size:0.78em;' + "\n" +
    '}';
var style = document.createElement('style');
style.appendChild(document.createTextNode(styleText));
document.getElementsByTagName('head')[0].appendChild(style);

/**
 * On window load, finish out the DOM and hook in the autocompleter.
 */
window.addEventListener('load', function(event) {

    // Grab the GCSAutocompleter which we added to the page previously.
    GCSAutocompleter = unsafeWindow['GCSAutocompleter'];
    
    // Adding the GCS Autocomplete functionality to all inputs with name='q'
    var firstq = null;
    var inputs = document.getElementsByTagName('input');
    for (var i=0; i<inputs.length && firstq==null; i++) {
        var q = inputs[i];
        if (q.name != 'q') continue;
        q.id = 'q' + i;
        var td = q.parentNode;
        var div = document.createElement('div');
        div.id = 'q_autocomplete' + i;
        div.className = 'autocomplete';
        div.style.display = 'none';
        td.appendChild(div);
        new GCSAutocompleter(
            q.id,
            div.id,
            'codesearch',
            { tokens: ' ', limit: '30', defaultParams: 'btnG=Search&num=30', method: 'get'}
        );
        if (!firstq) firstq = q;
    }
    firstq.focus();
}, 'false');

})(); // end anonymous function wrapper