0

I'm currently having a problem. I have a div containing html. But if the html inside the div is too long, I want it to be shortened and three dots added in the end. Now with plain text this would be no problem. With html my problem is this. Lets say i have

<div>
    Some <a href="someurl">LinkText</a> and a 
    <span class="this-class">special formatting that's also <b>bold</b></span>
</div>

Now if i implement this with

$(theSelector).html($(theSelector).html().substring(0,50));

will lead to something like this (I didn't count the exact length ;))

<div>
    Some <a href="someurl">LinkText</a> and a 
    <span class="this-

so i will end up with corrupt html. The easy way to solve this would be just to use the text and not the html but i want to keep the formatting. Can anyone think of a way to nicely shorten this but also close all tags again correctly?

2
  • 1
    How about using CSS for this kind of task Commented Nov 30, 2017 at 10:15
  • Do you want a trailing reticences in your string or do you want that to be displayed? Commented Nov 30, 2017 at 10:16

2 Answers 2

4

Your best bet is not to solve this at the HTML/JavaScript level at all. Instead, use CSS's overflow: hidden and text-overflow: ellipsis (you may also need white-space: nowrap):

.limit {
  width: 20em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
<div class="limit">
    Some <a href="someurl">LinkText</a> and a 
    <span class="this-class">special fomatting that's also <b>bold</b>
    </span>
</div>

Sadly it will happily add the ellipsis in the middle of a word (see this question), but your JavaScript would as well, so...

But if for some reason you can't do that and you do actually need to modify the DOM, I would do it by working through the text nodes, not working at an HTML level:

function applyEllipsis(target, chars) {
  var i, child, text;
  // Loop through child nodes, counting off characters from `chars` until we've
  // accounted for them all
  i = 0;
  while (i < target.childNodes.length) {
    child = target.childNodes[i];
    if (chars <= 0) {
      // Remove any remaining nodes
      target.removeChild(child);
    } else {
      switch (child.nodeType) {
        case Node.TEXT_NODE:
          // Normalize whitespace
          child.nodeValue = child.nodeValue.replace(/[\s\r\n]+/g, " ");
          if (child.nodeValue.length >= chars) {
            // We're all done, trim and add the ellipsis
            child.nodeValue = child.nodeValue.substring(0, chars) + "\u2026";
            chars = 0;
          } else {
            // Not done yet, subtract the number we've seen
            chars -= child.nodeValue.length;
          }
          break;
        case Node.ELEMENT_NODE:
          // Recurse
          chars = applyEllipsis(child, chars);
          break;
      }
      
      // Move to next child
      ++i;
    }
  }
  return chars;
}
applyEllipsis(document.querySelector(".limit"), 50);
<div class="limit">
    Some <a href="someurl">LinkText</a> and a 
    <span class="this-class">special fomatting that's also <b>bold</b>
    </span>
</div>

You may have to tweak that a bit but it should get you going the right way. In particular, it counts a single whitespace character at the beginning of a block display element (e.g., between <div class="limit"> and Some) which won't be displayed as a space by the browser.

Sign up to request clarification or add additional context in comments.

2 Comments

Awesome this is the best
Thanks... That's exactly what I was looking for. The more you know ;)
0

Try like this, using regular expression

var regex = /(<([^>]+)>)/ig
var html = jQuery("#container").html();
var result = html.replace(regex, "");
console.log(result.substr(0,50));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
    Some <a href="someurl">LinkText</a> and a 
    <span class="this-class">special fomatting that's also <b>bold</b>
    </span>
</div>

3 Comments

yeah you can also use css
Now, you know this is dangerous, right? ;-)
Yes! CSS is best way to do this :) go with css

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.