Text selection --> Google search
posted Jun 06, 2003

Selecting text on a page causes a search button to pop up. It might be non-annoying enough to be useful.

Update: Turns out that Firebird has this same feature built in. Select some text, and right-click on the selection. One of the menu options is "web search." Dang, I'm dumb for not realizing this.

When you select any text on this page, a little G should appear near the mouse cursor. Click it to open up a Google search window for the selected text. All the javascript is in the source of this page. Some explanation is given below.

Example:

It is not the critic who counts,
not the man who points out how the strong man stumbled,
or where the doer of deeds could have done them better.

The credit belongs to the man who is actually in the arena;
whose face is marred by dust and sweat and blood;who strives valiantly;
who errs and comes short again and again;
who knows the great enthusiasms, the great devotions,
and spends himself in a worthy cause;
who, at the best knows the triumph of high achievement;
and who, at the worst, if he fails, at least fails while daring greatly,
so that his place shall never be with those cold and timid souls
who know neither victory nor defeat.

- Theodore Roosevelt

Notes

I first saw something like this at astrobio.net. I don't know who the original author is. The little "G" popup box is my own creation.

The version at astrobio.net opens up a search window automatically, with each selection. It also tries to do some intelligent filtering, to block very small or very large selections. But the filtering was pretty crude. Worse, it was annoying because I didn't want a search every time I selected something.

There needed to be some way to quickly trigger a search. Thus, the little "G" box. It's a stab at balancing the utility of quick search access against the distraction of interface clutter.

Right now, the little "G" box appears under the mouse cursor when the selection is completed. I wanted it to appear at the lower-right corner of the selection, but there doesn't appear to be a simple way to do this. There may be complicated ways. I tried a few.

IE uses the textrange object to provide bounding boxes for text selections. But it can't pinpoint the end of a selection, just the rightmost boundary. So if the selection were multiple lines, the box would appear at the far right of the longest line, not at the end of the highlighted text.

Mozilla uses the range object, and it doesn't automatically provide bounding boxes. It seems to give an entry point into the DOM tree, which a script can (hopefully?) use to calculate the text selection endpoint from the lower-level DOM node properties. Boy, that sounds like a ton of fun.

How it works:

The first ingredient is a little "G" box:

<a id="g_box" 
      class="g_box" 
      style="position:absolute;visibility:hidden;" 
       href="javascript:google_search();" 
onmouseover="google_search_mouseover_status();return true;" 
 onmouseout="window.status = 'Done';">
G
</a>

We also need to style the little "G" box:


a.g_box {
  display:block;
  margin:1px;
  padding:1px;
  color: #0000ff;
  border: solid 1px;
  background-color:#ffffff;
  border-color: #00ff00 #ff0000 #00ff00 #0000ff;
  font-family:Garamond,serif;
  font-size:9pt;
  font-weight:bold;
  line-height:90%;
  text-decoration:none;
  z-index:1000;
}

When styled, it looks like: G

Notice that it's a link to javascript:google_search(). More about that function later.

The inline style is set to style="position:absolute;visibility:hidden;"
So it's actually invisible.

It's only going to become visible after the user makes a selection. For that, we need to detect mouseup and mousedown.


if (window.Event) {
 document.captureEvents(Event.MOUSEUP);  
 document.captureEvents(Event.MOUSEDOWN); 
}
document.onmouseup = mouseup;
document.onmousedown = mousedown;

function mousedown(e) 
{
  update_mouse_coords(e);
  setTimeout('g_box_hide()',10);   // hide the "G" after 10 ms.
                                   // Doing it right away makes things not behave right (try it and see).
}

function mouseup(e) 
{
  update_mouse_coords(e);          // get current mouse coordinates
  var str = get_selection();       // see what's selected
  if (str.length == 0) return;     // if nothing is selected return
  setTimeout('g_box_show()',10);   // display a little "G" in 10 ms 
                                   // Doing it right away makes things not behave right (try it and see).
}

And when we detect mouseup and mousedown, we hide or show the box:


function g_box_hide() 
{
  var str = get_selection();
  if (str.length != 0) return;     // if nothing is selected
  
  var g_box = document.getElementById("g_box");
  g_box.style.visibility = "hidden";
}

function g_box_show() 
{
  var g_box = document.getElementById("g_box");
  if (g_box.style.visibility == "visible") return;
  
  if (window.getSelection) // Moz
  {  
    g_box.style.left = mouse_x;
    g_box.style.top =  mouse_y;
  } 
  else if (document.selection && document.selection.createRange) // IE
  { 
    g_box.style.left = mouse_x;
    g_box.style.top =  mouse_y;
    
    // experimental stuff for using IE textrange to put
    // the G box at the end of the selection
  
    //var range = document.selection.createRange();
    //var corner_x=range.boundingLeft+range.boundingWidth;
    //var corner_y=range.boundingTop+range.boundingHeight;
    //alert("corner x: "+corner_x+" corner y: "+corner_y);
    //g_box.style.left = corner_x;
    //g_box.style.top = corner_y;
  }
  g_box.style.visibility = "visible";
}

Of course, we should figure out where to put the thing first.


function update_mouse_coords(e)
{  
  if (window.getSelection) {  // Moz
    mouse_x=e.layerX;
    mouse_y=e.layerY;    
  } else if (document.selection && document.selection.createRange) { // IE
    mouse_x=window.event.clientX+document.body.scrollLeft-4;
    mouse_y=window.event.clientY+document.body.scrollTop-4;
  } else { // out-of-luck below v.4
    var str = "";
    //alert("Sorry, event capture is not possible with your browser.");
    return;
  }
}

Actually doing the search is the easy part:

function google_search() 
{
  var target='http://www.google.com/search?hl=en&ie=UTF-8&q=';
  var str = get_selection();
  self.name = "body";
  msgWindow = window.open(target + str, "displayWindow", "location=yes,menubar=yes,toolbar=yes,scrollbars=yes,resizable=yes,height=480,width=500,screenX=0,left=0,screenY=0,top=0");
}

function get_selection() 
{
  var str = new String("");
  if (window.getSelection)   // Moz
  {
    str = window.getSelection().toString();
  } 
  else if (document.selection && document.selection.createRange) // IE
  { 
    var range = document.selection.createRange();
    str = range.text.toString();
  } 
  else // out-of-luck below v.4
  { 
    //alert("Sorry, event capture is not possible with your browser.");
  }
  // remove non-alphanumeric stuff from the string
  str = str.replace(/[^a-zA-Z 0-9]+/g,'');
  return str;
}

For consistency, we make the link show some information in the status bar when the cursor is over it.


function google_search_mouseover_status() // my_function_name_is_longer_than_your_function_name_ha_ha
{
  var str = get_selection();
  window.status = "Google search for \""+str+"\"";
  return true;
}

Comment by Piers Johnson
posted Jun 22, 2003

Nice code, is there any way to stop an inverted comma within the selection truncating it? I assume you'd have to do this before the toString() method is used.

Comment by LPD
posted Aug 22, 2003

The toString() method doesn't have a problem with quotes (inverted commas).

Try select-searching on something on this page with double or single quotes, like the code.

Comment by kevin holland
posted Dec 09, 2003

doesn't work in MSIE 6.0

i get nothing when i highlight some text

Comment by Michael Johnson
posted Dec 14, 2003

Opera also has this functionality built in. Double click a word or right click a selection and a context menu comes up letting you copy, search, look up (dictionary or encyclopedia), translate, follow as a URL, or e-mail the selection. Wow.

Comment by LPD
posted Jan 23, 2004

I fixed the problem in IE 6.0. I had switched the doctype to XHTML 1.0 transitional, which means the "document.scrollTop" property no longer works in IE (it's replaced by document.documentElement.scrollTop). These pages give the solution:

<a href="http://www.quirksmode.org/js/doctypes.html</a>>

<a href="http://www.sitepoint.com/forums/archive/index.php/t-143442</a>>

Comment by 1beb
posted May 27, 2004

That's a pretty cool little toy... would be really interesting to implement on larger scale documents... like Linux docs... or other things that people 'talk about'

Comment by nate bates
posted Jun 30, 2004

very slick code... i found it on another guy's site and had to search for g_box to find the original code here. you should add a little comment taking credit for your work.

there's a little bug where if you double-click a word to select it and then single-click it to deselect it, the G will not go away. i believe the solution is:

in gboxhide(), comment out    var str = get_selection();    if (str.length != 0) return; // if nothing is selected

in gboxshow(), add to the top:    var str = getselection();    if (str.length == 0) { // if nothing is selected       gbox_hide();       return;    }

oh, and i added a little code at the end of gboxshow() to generate the tooltip for the link:    g_box.title = "Google search for \""+str+"\"";

and since i was using absolutely positioned divs, i had to use e.pageX and e.pageY instead of e.layerX and e.layerY within updatemousecoords(e).

again, thanks for the cool code, i hope my suggestions are helpful.

Comment by natebates
posted Jun 30, 2004

a correction to my post above. it's not necessary to change anything within gboxhide(), doing so will actually create a problem -- it will cause the G to move when clicking on the G. sorry about that...

Comment by Refused
posted Apr 26, 2005

Simple web link example. Create shortcut name "Google Search" Right Click & click properties copy below into "URL" field (NO carriage returns or spaces allowed!!) Click OK Copy into "Links" folder Select text in a web page Click "Google Search" from "Links" menu

javascript:q=(document.frames.length?'':document.selection.createRange().text);for(i=0;i<document.frames.length;i++){q=document.frames[i].document.selection.createRange().text;if(q!='')break;}if(q=='')void(q=prompt('Enter text to search using Google. You can also highlight a word on this web page before clicking Google Search.',''));if(q)location.href='

Comment by Refused
posted Apr 26, 2005

OK, the pasting of a script didn't work. This pages example is very cool but go http://www.google.com/options/winexplorer.html for a simple solution.

Comment by zobi
posted Apr 30, 2006

Everything worked fine except that clicking on the G doesn't open a new window on firefox or konqueror neither on this page nor on my page. Any idea why that might be? Looking forward to using it. Thanks.