views:

56

answers:

1

Hi everyone,

I want to implement the Google custom search API with Greasemonkey, and so far my trials have met with mostly failures. The goal of the code is to inject a custom search box into an existing site (I'm trying to do this for MATLAB's documentation pages, but the injected code should really work with any site). I have attempted many methods suggested by searches on the net(mostly pertaining to implementation of JQuery or Google language api in Greasemonkey) and none have worked for the custom search api...

I think there might be some problem with the variable scope, but please let me know if anyone has any suggestions on getting it to work...

// Inject the Google API loader script
var script = document.createElement('script'); 
script.src = 'http://www.google.com/jsapi?callback=gLoaded';  // Call gLoaded() when google api loader is ready.
script.type = "text/javascript"; 
document.getElementsByTagName('head')[0].appendChild(script); 

// Create the <div> tag for the search API to draw the search box
var elmBody = document.getElementsByTagName('Body')[0];
var gSearch = document.createElement('div');
gSearch.id = 'g_search';
elmBody.appendChild(gSearch);

// Let w be the shorthand for unsafeWindow under the Greasemonkey sandbox
var w = unsafeWindow;

// Load the search api using the Google API loader
w.gLoaded= function()
{ w.google.load('search','1', {"callback" : searchLoaded}); } ; // Run searchLoaded() when search API is ready

// Setup the custom search API and draw the search box
searchLoaded = function(){ 
google = w.google; // unsafeWindow
alert(google);                                   // :debug_1
alert(google.search);                            // :debug_2
alert(google.search.CurrentLocale);              // :debug_3
var mySearch= new google.search.CustomSearchControl('012907575288767046387:tuvzi3yqdkq');
alert(mySearch)                                  // :debug_4
mySearch.setResultSetSize(google.search.Search.FILTERED_CSE_RESULTSET);
mySearch.draw('g_search');  // Draw the search box to the <div id='g_search'>
} 
  • debug_1: Returns a valid object
  • debug_2: Returns a valid object
  • debug_3: Returns a valid string ('en')
  • debug_3: Returns undefined
  • Likewise I have tried letting searchLoaded -> w.searchLoaded and removed the statement (google = w.google) but in that case all debugs return undefined.

Interestingly, when I used the Javascript shell bookmarklet and reassigned the functions gLoaded() and searchLoaded() non-Greasemonkey counterparts(no unsafeWindow concerns) through the command line, everything just worked as intended. A lovely search box shows up where its supposed to be.

Besides any suggestions to get it working, I was wondering...

  1. How come google.search.CurrentLocale returned valid string, where as the constructor google.search.CustomSearchControl() could not be loaded?

  2. When I assigned searchLoaded as unsafeWindow.searchLoaded(see last note above), the google objects are no longer visible to the function even though they should be under the window scope by default. HOWEVER, when I assigned the function those very same values under the javascript shell, everything worked! Is Greasemonkey somehow shielding those variables even though I have explicitly defined the function to be in the window scope?

I have tried variations with different schemes(location hack, @required, google.setOnLoadCallback...), but none of them worked for me.

Please let me know of ANY... and I mean ANY suggestions, I'm running out of ideas...

Thanks!

+1  A: 

Basically...

var script = document.createElement('script'); 
script.type = "text/javascript"; 
script.innerHTML = (<><![CDATA[

// YOUR CODE GOES HERE

]]></>).toString();
document.getElementsByTagName('head')[0].appendChild(script);

Write the code as a normal script, not a GM script.
I mean, remove all unsafeWindow references and related stuff.
This will make the script to run in the correct scope.
The problem occurs because google.search.CustomSearchControl uses variables like J and K that are undefined in the GM scope.

w35l3y
Thanks! The code worked great with this trick.However, may I ask what is reason for including a <> and </> around the CDATA? I tried with and without the set and the code was working either way.
dpwave
teorically CDATA should always be inside a tagand this is the begin and end of my root tag, respectively
w35l3y