JSFiddle - React, Tailwind, and code Playground
HTML
<p class="truncated">
<streak>start</streak>
<streak>1</streak>
<streak>2</streak>
<double>3</double>
<double>4</double>
<span>5</span>
<span>6</span>
<streak>7</streak>
<streak>8</streak>
<double>9</double>
<double>10</double>
<streak>end</streak>
</p>
<p id="before"></p>
How to cut
<input id="count" type="number" min="1" autofocus required />
<button id="go">Go</button>
<p id="after"></p>
CSS
p {
margin: 0 0 5px 0;
display: block;
padding: 5px;
}
streak {
color: green;
}
double {
color: orange;
}
p span {
color: grey;
}
JavaScript
function cutKeepingTags(elem, reqCount) {
var grabText = '',
missCount = reqCount;
$(elem).contents().each(function() {
switch (this.nodeType) {
case Node.TEXT_NODE:
// Get node text, limited to missCount.
grabText += this.data.substr(0,missCount);
missCount -= Math.min(this.data.length, missCount);
break;
case Node.ELEMENT_NODE:
// Explore current child:
var childPart = cutKeepingTags(this, missCount);
grabText += childPart.text;
missCount -= childPart.count;
break;
}
if (missCount == 0) {
// We got text enough, stop looping.
return false;
}
});
return {
text:
// Wrap text using current elem tag.
elem.outerHTML.match(/^<[^>]+>/m)[0]
+ grabText
+ '</' + elem.localName + '>',
count: reqCount - missCount
};
}
var target = $('.truncated')[0];
$('#before')
.append('<pre>' + show(target.outerHTML) + '</pre>');
$('#go').click(function() {
$('#after').empty();
var cut = cutKeepingTags(target,$('#count').val());
$('#after')
.append(cut.text)
.append('<pre>' + show(cut.text) + '</pre>');
});
function show(html) {
return html.replace(/</g, '<').replace(/\n/g,'¶\n').replace(/ /g,'·');
}