Tengo un elemento HTML que puede contener texto sin formato u otros elementos HTML:
<!-- plain text --> <div class="content"> SIMPLE TEXT. </div> <!-- or other html elements --> <div class="content"> SIMPLE <span>TEXT.</span> <table> <tr> <td>1</td> <td>2</td> </tr> <tr> <td>a</td> <td>b</td> </tr> </table> </div> <!-- more html elements --> <div class="content"> SIMPLE <span>TEXT.</span> <div> OTHER TEXT WITH MORE <span>HTML!</span> </div> </div> <!-- one more example --> <div class="content"> SIMPLE <span>TEXT.</span> <div> OTHER TEXT WITH MORE <span>HTML</span>! </div> </div> ¿Cómo puedo agregar un elemento HTML más al último carácter imprimible en mi div .content , independientemente del elemento HTML en el que se encuentre el carácter?
Resultado Esperado:
<!-- plain text --> <div class="content"> SIMPLE TEXT.<span class="end"></span> </div> <!-- or other html elements --> <div class="content"> SIMPLE <span>TEXT.</span> <table> <tr> <td>1</td> <td>2</td> </tr> <tr> <td>a</td> <td>b<span class="end"></span></td> </tr> </table> </div> <!-- more html elements --> <div class="content"> SIMPLE <span>TEXT.</span> <div> OTHER TEXT WITH MORE <span>HTML!<span class="end"></span></span> </div> </div> <!-- one more example --> <div class="content"> SIMPLE <span>TEXT.</span> <div> OTHER TEXT WITH MORE <span>HTML</span>!<span class="end"></span> </div> </div>Aquí está mi enfoque para resolver este problema, el JQuery línea por línea y luego el fragmento de ejemplo.
Primer bucle a través de cada elemento .content :
$('.content').each(function(){Luego almacene en una var que es el último carácter:
var ch = $(this).text().trim().slice(-1); Ahora, dado que a veces el último carácter puede estar solo en un nodo de texto y no dentro de un elemento secundario de .content , necesitamos diferenciar esta condición, podemos identificar los elementos secundarios del último nodo de texto y el último elemento real.
var lastnode = $(this).contents().last(); var textnode = $(this).contents().filter(function(){ return this.nodeType === 3 && $.trim(this.nodeValue) !== '';; }).last(); Finalmente, si el último elemento secundario es un nodo de texto, solo necesitamos append() el elemento al padre .content , de lo contrario, busque el último elemento que :contains nuestro carácter almacenado y haga el append() :
$('.content').each(function(){ var ch = $(this).text().trim().slice(-1); var lastnode = $(this).contents().last(); var textnode = $(this).contents().filter(function(){ return this.nodeType === 3 && $.trim(this.nodeValue) !== '';; }).last(); if (lastnode[0] == textnode[0]) { $(this).append('<span class="end"></span>') } else { $(this).find(":contains('"+ch+"')").last().append('<span class="end"></span>') } }) .end { width: 10px; height: 10px; margin:0 5px; background: purple; display: inline-block; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <!-- plain text --> <div class="content"> SIMPLE TEXT. </div> <!-- or other html elements --> <div class="content"> SIMPLE<span>TEXT.</span> <table> <tr> <td>1</td> <td>2</td> </tr> <tr> <td>b</td> <td>b</td> </tr> </table> </div>Recurse a través de su elemento para obtener el último nodo de texto
https://jsfiddle.net/30ezoyau/
<div id="content"> SIMPLE <span>TEXT.</span> <table> <tr> <td>1</td> <td>2</td> </tr> <tr> <td>a</td> <td id="last">b</td> </tr> </table> </div>js
// get your root element const tree = document.querySelector('#content') // flatten your tree into a list, then pop it to get last text node const walk = (node = {}, list = []) => { // assuming you want the text node's parent node, not the text node itself if (/\w{1,}/i.test(node.textContent || '') && node.nodeName !== '#text') list.push(node) if (node.childNodes) { return [...node.childNodes].reduce((acc, child, i) => { const branch = walk(child, acc) return [...acc, ...branch] }, []) } else { return list } } // walk through tree to get last non-empty text node const lastString = walk(tree).pop() // append it lastString.innerHTML = lastString.innerHTML + `<b> is last</b>` // test console.assert( document.getElementById('last').innerHTML === 'b<b> is last</b>', 'should append span to last text' )para encontrar el último texto, necesitas una función recursiva como esta
function getLastText(element) { if (!element) return null; if (element.childNodes && element.childNodes.length > 0) { //alert('loop'); for (var i = element.childNodes.length - 1; i >= 0; i++) { var glt = getLastText(element.childNodes[i]); if (glt != null) { return glt; } } } if (element.textContent && element.textContent.length > 0) { return element; } return null; }Esto devolverá el último elemento que tiene texto contenido dentro del elemento en la llamada inicial getLastText