Tengo un website que convierte kanji japonés en romaji (letras romanas) :
y el resultado muestra y oculta con CSS
lo que el usuario necesita ver según sus criterios de input. Por ejemplo:
<div id="output"> <span class="roman">watashi</span> <span class="english">I</span> </div>
La interfaz permite al usuario cambiar entre watashi
y I
dependiendo de lo que quieran ver.
El CSS
oculta uno u otro usando jQuery
y un button para alternar. (el mecanismo de ocultamiento implica simplemente agregar una class al body
y dejar que CSS
haga su trabajo).
El problema es que cuando los usuarios copyn / pegan el text en Word
lo copy todo. Así que decidí usar un sistema para copyr y pegar el text usando JavaScript
y jQuery
, pero el problema se repite:
$('#output').text()
watashi I
incluso si I
invisible en la página en vez de watashi
. ¿Hay alguna manera de get solo el text visible?
Use el selector: visible de Jquery
En tu caso, creo que quieres hacer:
$('#output').children(":visible").text()
las otras soluciones no me dieron lo que necesitaba.
mi respuesta es :
$('#output *:not(:has(*)):visible').text()
Plunkr
No debe preguntar el text de todos los elementos debajo de algún elemento raíz.
¿por qué? – repetirá la salida e ignorará la bandera oculta
veamos un ejemplo simple
<div id="output" class="my-root"> <div class="some-div"> <span class="first" style="display:none"> hidden text </span> <span class="second" > visible text </span> </div> <div>
ahora si hago $('#output').children(":visible").text()
.second
.some-div
y .second
… cuando de hecho. .second
.some-div
no me concierne …
cuando pido text()
sobre esos elementos, .some-div
devolverá el text oculto también ..
por lo que técnicamente la solución de marcgg es incorrecta en mi humilde opinión …
Ahora, para responder correctamente a la pregunta, tenemos que hacer una suposition. Uno que, para mí, parece bastante razonable.
La suposition es que el text solo aparece en elementos de hoja.
Entonces no veremos algo como esto:
<div id="output" class="my-root"> <div class="some-div"> <span class="first" style="display:none"> hidden text </span> <span class="second" > visible text </span> </div> some text here.. <div>
¿Por qué esta suposition parece razonable para mí? dos razones:
Con esa suposition, lo que quiere hacer es solicitar todos los elementos de hoja (elementos sin elementos secundarios), filtrar lo visible y solicitar su text.
$('#output *:not(:has(*)):visible').text()
Esto debería generar el resultado correcto.
los comentarios sugieren que a veces tienes que tener text fuera del elemento de la hoja
<div> This is some <strong style="display:none"> text </strong> </div>
Como puede ver, tiene <strong>
como hoja y es común tener text fuera de este como en este ejemplo.
Podrías darle la vuelta con la solución que sugiero arriba … pero ¿y si no puedes?
Puedes clonar el dom y luego eliminar todos los elementos ocultos. El problema aquí es que para que el selector :visible
o :hidden
selectores :hidden
funcionen, debo tener el elemento dom en el documento (lo que significa realmente visible para el usuario). Y entonces, este método viene con algunos efectos secundarios, así que ten cuidado.
Aquí hay un ejemplo
para este html
<div id="output" class="my-root"> <span> some text <strong style="display:none">here.. </strong> </span> </div>
Este javascript funciona
$(function(){ var outputClone = $('#output').clone(); $('#output :hidden').remove(); console.log($('#output').text()); // only visible text $('#output').replaceWith(outputClone); console.log($('#output').text()); // show original state achieved. })
ver plunker aquí
como se mencionó, los efectos secundarios pueden aparecer como un parpadeo momentáneo o algún script de initialization que debería ejecutarse … algunos pueden evitarse con un pensamiento original (div con tamaño 1px / 1px para contener el clon junto con el contenido original) dependiendo de su escenario.
Guy tiene la respuesta correcta.
Sin embargo, estaba lidiando con un object "este", por lo que para que funcione su respuesta necesita usar la siguiente syntax …
$('*:not(:has(*)):visible', this).text()
var lookup = function(element, text) { //DFS Recursive way of finding text on each level //Visible only works on elements that take up space(ie not fixed position elements) var results = element.children(':visible'); //Look at the text at each level with the children removed var newText = ''; results.each(function(index, value) { newText += $(value).clone() .children() .remove() .end() .text(); }); var moreResultText = ''; results.each(function(index, value) { moreResultText += lookup($(value), text); }) if (results.length > 0) { return text + newText + moreResultText; } else { return text; } }; lookup($('#output'), ''));
La mayoría de las otras funciones se desmoronan cuando se ejecutan en grandes secciones de una página, esta debería ser una manera más precisa de determinar qué se muestra realmente al usuario, sin corromper la página y sin devolver el text que no sea visible para el usuario.
Tenga cuidado, por supuesto, esto no conserva ningún sentido de formateo, y el espaciado de la salida puede no ser correcto entre los elementos. Además, probablemente no ordere correctamente el text devuelto, en estos aspectos sus usos serán limitados. Otra consideración es que la definición real de visible es un poco difícil de definir, pero para este ejemplo acepto que "visible" funciona para la mayoría de los casos comunes.
Lo uso para verificar si una página contiene text visible (simplemente ejecútelo en el elemento del cuerpo), pero probablemente también funcione para este ejemplo.
En lugar de ocultar un tramo, elimine el elemento tramo y conserve una reference al mismo. Cuando el usuario click el button de alternar, elimine el otro e inserte el que tenía referencedo. El usuario ya no podrá seleccionar algo que ya no esté en DOM.
Pruebe esto en browseres modernos (aquí 'elemento' es un object DOM no JQuery):
function getVisibleText(element) { window.getSelection().removeAllRanges(); var range = document.createRange(); range.selectNode(element); window.getSelection().addRange(range); var visibleText = window.getSelection().toString().trim(); window.getSelection().removeAllRanges(); return visibleText; }
entonces:
getVisibleText(document.getElementById('output'));