Pregunta

¿Hay alguna forma de encontrar el texto seleccionado en un documento HTML si el texto puede estar dentro de uno de sus marcos (o iframes)?

Si el documento no tiene marcos, es 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

Entonces, esto funciona entre navegadores (aunque no muy bonito).

El problema es cuando el documento contiene marcos o iframes. Los marcos tienen su propio documento, por lo que no basta con usar el código anterior. Potencialmente, uno podría iterar sobre el árbol de marcos y buscar el texto seleccionado en uno de ellos, sin embargo, en general, los marcos pueden tener contenido de diferentes dominios, por lo que incluso si tuviera que iterar sobre todos los marcos y sobre todos los subtramas, etc. del documento raíz en la búsqueda del texto seleccionado no habría tenido permiso para acceder a su HTML, ¿verdad? Por lo tanto, no podría obtener el texto seleccionado.

¿Existe una forma (simple) confiable de encontrar el texto seleccionado en una página web incluso si la página contiene marcos?

Gracias

¿Fue útil?

Solución

Para responder mi propia pregunta, después de un poco más de investigación: Entonces, si los marcos son de diferentes dominios, entonces no hay nada que pueda hacer al respecto, ya que no tiene permiso para acceder a su dom. Sin embargo, en el caso común en el que todos los marcos están en el mismo dominio (por ejemplo, gmail) solo itera el tema como un árbol. Aquí está el código que logra eso:

El siguiente código es para un marcador que cuenta caracteres y palabras del texto seleccionado:

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

Otros consejos

@Ran Excelente respuesta a tu propia pregunta. Sin embargo, si el documento del iframe no está definido, la función falla. Agregué un condicional para verificar esto, ahora funciona en todos los sitios que he probado, incluido Gmail. if ((! t || t == '') & amp; & amp; d) Gracias de nuevo por el gran 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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top