I have a given text with t-tags before some words. Inside the t-tags is the id of the word before the tag, which I have to find and replace with some html-code. What I have so far seems too complicated and also does not work, because the replaced html is printed as text and not as html.
Anybody an idea of a better, easier and working solution?
JSFiddle: https://jsfiddle.net/fsdx2o7h/18/
This is the first<t>element1</t>. This is the second<t>element2</t>. This is the third<t>element3</t>.
$('t').each(function() {
var prevText = this.previousSibling.nodeValue;
var arrPrevText = prevText.split(' ');
var nrElements = arrPrevText.length;
var textpart = arrPrevText[nrElements-1];
var id = $(this).html();
arrPrevText[nrElements-1] = "<span id='" + id + "'>" + textpart + "</span>";
this.previousSibling.nodeValue = arrPrevText.join(' ');
});
It can be a bit simpler, yes, but you were on the right track. See comments:
$('t').each(function() {
// Get our previous sibling
var prev = this.previousSibling;
// If not a text node, quit
if (prev.nodeType !== 3) {
return;
}
// Get the text of it
var text = prev.nodeValue;
// Find the last word; if none, quit
var index = text.lastIndexOf(" ");
if (index < 0){
return;
}
// Skip past the space prior to the word
++index;
// Grab the word
var word = text.substring(index).trim();
// Remove it from the text node
prev.nodeValue = text.substring(0, index);
// Replace this `t` element with a span using
// the word as its text and this `t` element's
// innerHTML as its ID
$(this).replaceWith(
$("<span>").text(word).attr("id", this.innerHTML)
);
});
span[id] {
color: red;
}
This is the first<t>element1</t>. This is the second<t>element2</t>. This is the third<t>element3</t>.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
While you've already accepted an answer I though I'd post what I feel is a slightly simpler alternative (note that I'm unsure as to whether or not the <t> element should be removed or not):
// selecting the <t> elements, and using the before()
// method to insert new contents ahead of each of the
// elements in the collection:
$('t').before(function() {
// caching the 'this' (the current <t> element):
var cached = this,
// finding the previous sibling of the current
// <t> element:
prevNode = cached.previousSibling,
// splitting that previous textNode (without first
// checking that it is a textNode, this will lead
// to errors in live code if you're working with
// unanticipated structures) into two textNodes
// at the index of the last index of a white-space,
// adding 1 to that index in order that we get the
// last word, without the space character, into its
// own textNode:
newPrevNode = prevNode.splitText(prevNode.nodeValue.lastIndexOf(' ') + 1),
// creating a <span> element:
span = document.createElement('span');
// setting the id of the new <span> element to the
// text of the current <t> element, after first
// removing leading and trailing white-space
// using String.prototype.trim():
span.id = cached.textContent.trim();
// appending the newPrevNode to the <span>:
span.appendChild(newPrevNode);
// returning the created <span> to the method for
// insertion ahead of the current <t> element:
return span;
// I'm unsure if you want to remove the <t> elements, if
// you do we can do that using the remove() method (the
// before() method returns the original collection, not
// the newly-inserted elements); if you don't want to
// remove the <t> elements simply omit the call to remove():
}).remove();
$('t').before(function() {
var cached = this,
prevNode = cached.previousSibling,
newPrevNode = prevNode.splitText(prevNode.nodeValue.lastIndexOf(' ') + 1),
span = document.createElement('span');
span.id = cached.textContent.trim();
span.appendChild(newPrevNode);
return span;
}).remove();
span {
color: #f90;
}
span::after {
content: ' (#' attr(id)') ';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This is the first
<t>element1</t>. This is the second
<t>element2</t>. This is the third
<t>element3</t>.
JS Fiddle demo.
The above approach uses a relatively minimal amount of jQuery, but requires jQuery nonetheless; below is a plain JavaScript alternative:
// converting the NodeList returned by document.querySelectorAll() into
// an Array, using Array.from(); and iterating over that Array of <t>
// elements using Array.prototype.forEach():
Array.from(document.querySelectorAll('t')).forEach(function(elem) {
// 'elem' : a reference to the current array-element of the
// array over which we're iterating.
// caching that array-element (partially this is laziness since it
// meant I could assign the variable here and not have to change
// 'cached' to 'elem' in copying from the above jQuery snippet):
var cached = elem,
// retrieving the previousSibling, the textNode:
prevNode = cached.previousSibling,
// splitting that textNode into two textNodes at the index,
// plus one, of the last white-space character; this returns
// the newly-created textNode (the one 'broken off' from the
// existing textNode):
newPrevNode = prevNode.splitText(prevNode.nodeValue.lastIndexOf(' ') + 1),
// creating a <span> element:
span = document.createElement('span');
// setting the id of the <span> to the text of the
// current <t> element, after first removing
// leading and trailing white-space using
// String.prototype.trim():
span.id = cached.textContent.trim();
// appending the newly-created/'broken off'
// textNode to the <span>:
span.appendChild(newPrevNode);
// using Node.insertBefore() to insert the
// <span> ahead of the current <t> element:
cached.parentNode.insertBefore(span, cached);
// using Node.removeChild() to remove the
// current <t> element from the DOM; again:
// omit this line if you wish to retain
// the <t> elements in the DOM:
cached.parentNode.removeChild(cached);
});
Array.from(document.querySelectorAll('t')).forEach(function(elem) {
var cached = elem,
prevNode = cached.previousSibling,
newPrevNode = prevNode.splitText(prevNode.nodeValue.lastIndexOf(' ') + 1),
span = document.createElement('span');
span.id = cached.textContent.trim();
span.appendChild(newPrevNode);
cached.parentNode.insertBefore(span, cached);
cached.parentNode.removeChild(cached);
});
span {
color: #f90;
}
span::after {
content: ' (#' attr(id)') ';
}
This is the first
<t>element1</t>. This is the second
<t>element2</t>. This is the third
<t>element3</t>.
JS Fiddle demo.
References:
document.createElement().Node.appendChild().Node.insertBefore().Node.nodeValue.Node.parentNode.Node.previousSibling.Node.removeChild().String.prototype.lastIndexOf().String.prototype.trim().Text.splitText().before().remove().If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With