JSFiddle - React, Tailwind, and code Playground
HTML
<p>It's the end of the world as we know it,<br>
and I feel fine</p>
<a>the</a><br>
<a><span>the</span></a>
CSS
em.ends-with-vowel { background:yellow }
JavaScript
// Record all the text nodes before we modify the tree,
// otherwise we will re-process entries already processed
var textNodes = findAllTextNodes(document.body);
var wordsEndingInVowel = /\b\w*[aeiou]\b/gi;
textNodes.forEach(function(textNode){
textNodeReplace(textNode,wordsEndingInVowel,function(matched){
if (matched.length>1) // We only wrap multi-letter words
return {
name:'em',
attrs:{"class":'ends-with-vowel'},
content:{ name:'b', content:matched }
};
else
// Just surround single-letter words with underscores
return "_"+matched+"_";
});
});
function findAllTextNodes(n){
var walker = n.ownerDocument.createTreeWalker(n,NodeFilter.SHOW_TEXT);
var textNodes = [];
while (walker.nextNode())
if (walker.currentNode.parentNode.tagName!='SCRIPT' && walker.currentNode.parentNode.tagName != 'A' )
textNodes.push(walker.currentNode);
return textNodes;
}
function textNodeReplace(node,regex,handler) {
var mom=node.parentNode, nxt=node.nextSibling,
doc=node.ownerDocument, hits;
if (regex.global) {
while(node && (hits=regex.exec(node.nodeValue))){
regex.lastIndex = 0;
node=handleResult( node, hits, handler.apply(this,hits) );
}
} else if (hits=regex.exec(node.nodeValue))
handleResult( node, hits, handler.apply(this,hits) );
function handleResult(node,hits,results){
var orig = node.nodeValue;
node.nodeValue = orig.slice(0,hits.index);
[].concat(create(mom,results)).forEach(function(n){
mom.insertBefore(n,nxt);
});
var rest = orig.slice(hits.index+hits[0].length);
return rest && mom.insertBefore(doc.createTextNode(rest),nxt);
}
function create(el,o){
if (o.map) return o.map(function(v){ return create(el,v) });
else if (typeof o==='object') {
var e = doc.createElementNS(o.namespaceURI || el.namespaceURI,o.name);
if (o.attrs) for (var a in o.attrs) e.setAttribute(a,o.attrs[a]);
if (o.content)...