views:

1161

answers:

1

Is there a way to find the selected text in an HTML document if the text may be within one of its frames (or iframes)?

If the document has no frames it's simple:

var text;
if (document.getSelection) {
 // Firefox and friends
 text = document.getSelection();
} else if (document.selection) {
 // IE 
 text = document.selection.createRange();
}
if (text == undefined || text == '') {
 // Iterate over all textarea elements and see if one of them has selection
 var areas = document.getElementsByTagName('textarea');
 for(var i = 0; i = areas.length; i++) {
  if(areas[i].selectionStart != undefined && 
     areas[i].selectionStart != areas[i].selectionEnd){
   text = areas[i].value.substring(areas[i].selectionStart, a[i].selectionEnd);
   break;
  }   
 }   
}
// Now if document has selected text, it's in text

So this works cross-browser (although not very pretty).

The problem is when the document contains frames or iframes. Frames have their own document, so just using the code above is not enough. One could potentially iterate over the frames tree and search for selected text in one of them, however in general frames can have content from different domains, so even if I were to iterate over all frames and over all subframes etc of the root document in search of selected text I would not have had the permission to access their HTML, right? So I wouldn't be able to get their selected text.

Is there a (simple) reliable way of finding the selected text on a web page even if the page contains frames?

Thanks

+1  A: 

To answer my own question, after a bit more investigation: So, if frames are of different domains then there's nothing you can do about it since you have no permission accessing their dom. However, in the common case where all frames are on the same domain (e.g. gmail) just iterate theme all like a tree. Here's the code that accomplishes that:

The code below is for a bookmarklet that counts chars and words of the selected text:

javascript:(function(){
  // Function: finds selected text on document d.
  // @return the selected text or null
  function f(d){
    var t;
    if (d.getSelection) t = d.getSelection();
    else if(d.selection) t = d.selection.createRange();
    if (t.text != undefined) t = t.text;
    if (!t || t=='') {
      var a = d.getElementsByTagName('textarea');
      for (var i = 0; i < a.length; ++i) {
        if (a[i].selectionStart != undefined && a[i].selectionStart != a[i].selectionEnd) {
          t = a[i].value.substring(a[i].selectionStart, a[i].selectionEnd);
          break;
        }
      }
    }
    return t;
  };
  // Function: finds selected text in document d and frames and subframes of d
  // @return the selected text or null
  function g(d){
    var t;
    try{t = f(d);}catch(e){};
    if (!t || t == '') {
      var fs = d.getElementsByTagName('frame');
      for (var i = 0; i < fs.length; ++i){
        t = g(fs[i].contentDocument);
        if(t && t.toString() != '') break;
      }
      if (!t || t.toString() == '') {
        fs = d.getElementsByTagName('iframe');
        for (var i = 0; i < fs.length; ++i){
          t = g(fs[i].contentDocument);
          if(t && t.toString() != '') break;
        }
      }
    }
    return t;
  };
  var t= g(document);
  if (!t || t == '') alert('please select some text');
  else alert('Chars: '+t.toString().length+'\nWords: '+t.toString().match(/(\S+)/g).length);
})()
Ran