Pergunta

Existe uma maneira de encontrar o texto selecionado em um documento HTML se o texto pode estar dentro de um de seus quadros (ou iframe)?

Se o documento não tem quadros É simples:

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

Então, isso funciona cross-browser (embora não muito bonita).

O problema é quando o documento contém frames ou iframes. Quadros têm o seu próprio documento, por isso apenas usando o código acima não é suficiente. Poderíamos potencialmente interagir sobre a árvore de quadros e procurar texto selecionado em um deles, no entanto, em quadros gerais pode ter conteúdo de domínios diferentes, por isso mesmo que eu fosse para iterar sobre todos os quadros e sobre todo subframes etc do documento raiz em busca do texto selecionado eu não teria tido a permissão para acessar o seu HTML, certo? Então, eu não seria capaz de obter o seu texto selecionado.

Existe uma (simples) maneira confiável de encontrar o texto selecionado em uma página web, mesmo que a página contém frames?

Graças

Foi útil?

Solução

Para responder a minha própria pergunta, depois de um pouco mais de investigação: Então, se os quadros são de domínios diferentes, então não há nada que você possa fazer sobre isso desde que você não tem permissão de acessar seu dom. No entanto, no caso comum, onde todos os quadros estão no mesmo domínio (por exemplo gmail) apenas tema iterate tudo como uma árvore. Aqui está o código que realiza o seguinte:

O código abaixo é para um bookmarklet que conta caracteres e palavras do texto selecionado:

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);
})()

Outras dicas

@Ran Excelente resposta à sua própria pergunta. No entanto, se o documento iframe é indefinido, em seguida, a função falha. Eu adicionei uma condicional para verificar isso, agora ele funciona em todos os sites que eu tentei incluindo Gmail. if ((!t || t == '') && d) Obrigado novamente para o grande código.

var getSelectedText = 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){console.log('ERROR: ',e);};
    if ((!t || t == '') && d){
      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 == '') ;
  else return t.toString();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top