Wednesday, June 13, 2012

Adding prefix logic to the ribbon search box

A common scenario when upgrading from SharePoint search to FAST Search for SharePoint is that you want to run the new search solution side by side with the old until you are comfortable switching.
image
One solution is having two search centers which targets the old and the new index. In my experience end-users find it cumbersome to navigate to the new search center in order to do testing because they want to use the search box in the ribbon as the entry point to the search center. The chosen solution for this post is to allow users to enter a prefix character in the search box to opt-in to use the new search engine.

I usually choose to use # as the prefix character. Searching for fs4sp would search the SharePoint index while #fs4sp would search the FAST Search for SharePoint index.

One solution to accomplish this is to create your own search box control with a custom script for handling the prefix character. A better and also easier solution is to override the way the existing search box executes queries.

The ribbon search box is implemented as a delegate control using SearchBoxEx. What happens when you click the search button in the SearchBoxEx control is that a javascript function called GoSearch() located in search.js is being executed. GoSearch takes several parameters, where two of them are the location of your site collection search center and the site collection result page, and one contains the html DOM id of the search input box. These parameters are the ones you want to use in order to change which search center the query is executed against.

The signature of GoSearch looks like this, where I have explained a few of the parameters.
// G = query - ctrl id
// F = scope - ctrl id
// D = current site url
// n = search center result url - absolute
// A = OSS result url - relative
function GoSearch(q,G,p,E,r,F,D,C,B,j,n,z,y,x,w,A,l,v)

What we want to do is override the GoSearch function, check for the prefix character (#), and if present, modify the url’s to the search result pages. By taking advantage of javascript’s ability to redefine function you simply emit the following script to your page in order to check for the prefix character and if present redirect the search query to the FS4SP search center.

function Override() {
    // Grab a reference to the existing GoSearch function
    var oldFunc = GoSearch;
    GoSearch = function (q, G, p, E, r, F, D, C, B, j, n, z, y, x, w, A, l, v) {
        // Get a reference to the search box
        var queryCtrl = document.getElementById(G);
        // Pick out the search query
        var query = queryCtrl.value;
        // redirect to FS4SP farm on # prefix
        if (query.indexOf('#') == 0) {
            queryCtrl.value = query.substring(1); // strip starting #
            n = 'http://fs4sp/Pages/results.aspx'; //FS4SP search center
            A = 'http://fs4sp//Pages/results.aspx'; //FS4SP search center
        }
        // Call the original GoSearch function in search.js
        oldFunc(q, G, p, E, r, F, D, C, B, j, n, z, y, x, w, A, l, v);
    }
}

When you register the script you have to make sure it’s being loaded after search.js has been loaded in order to get a reference to the existing GoSearch function. You can do this in SharePoint with the following line of javascript code:

ExecuteOrDelayUntilScriptLoaded(Override,'search.js');

How you go about adding the script is up to you. In my current project we are already creating a custom SearchBoxEx, so we added it to OnPreRender with this.Page.ClientScript.RegisterStartupScript. We also change the search center url based on a config setting as we have four environments in total.  But it could be added at any place you see fit.