I have a string which contains a lot of text, text, in my JavaScript file. I also have an element, div#container that is styled (using separate CSS) with potentially nonstandard line-height, font-size, font-face, and maybe others. It has a fixed height and width.
I’d like to get the maximum amount of text that can fit into div#container without any overflow from the string. What’s the best way of doing this?
This needs to be able to work with text formatted with tags, for example:
<strong>Hello person that is this is long and may take more than a</strong>
line and so on.
Currently, I’ve got a JQuery plugin that works for plain text, code follows:
// returns the part of the string that cannot fit into the object
$.fn.func = function(str) {
var height = this.height();
this.height("auto");
while(true) {
if(str == "") {
this.height(height);
return str; // the string is empty, we're done
}
var r = sfw(str); // r = [word, rest of String] (sfw is a split first word function defined elsewhere
var w = r[0], s = r[1];
var old_html = this.html();
this.html(old_html + " " + w);
if(this.height() > height)
{
this.html(old_html);
this.height(height);
return str; // overflow, return to last working version
}
str = s;
}
}
UPDATE:
The data looks like this:
<ol>
<li>
<h2>Title</h2>
<ol>
<li>Character</li>
<ol>
<li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
<li>Line two can be separated from line one, but not from itself</li>
</ol>
</ol>
<ol>
<li>This can be split from other</li>
<ol>
<li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
<li>Line two can be separated from line one, but not from itself</li>
</ol>
</ol>
</li> <li>
<h2>Title</h2>
<ol>
<li>Character</li>
<ol>
<li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
<li>Line two can be separated from line one, but not from itself</li>
</ol>
</ol>
<ol>
<li>This can be split from other</li>
<ol>
<li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
<li>Line two can be separated from line one, but not from itself</li>
</ol>
</ol>
</li>
</ol>
well, let me try to solve it 😉 actually thinking about solution I noticed that I don’t know enough about requirements you have, so I decided to develop simple JavaScript code and show you result; after trying it you can tell me what’s wrong so I can fix/change it, deal?
I used pure JavaScript, no jQuery (it can be rewritten if needed). The principle is similar to your jQuery plugin:
sfwfunction does; it can be changed)container.innerHTML = "My String has a link <a href='#'";in browser I see “My String has a link“, so “unfinished” tag does not influence size of container (at least in all browsers where I tested)HTML page to test it:
Possible improvements / changes:
fullTextback into container if needed (which I also do not change)sfwfunction, so you can change it easily."our sentence", it is possible that visible will be only first one ("our"), and “sentence” should be cut (overflow:hiddenwill work this way). In my case, I will append character by character, so my result can be"our sent". Again, this is not a complex part of algorithm, so based on your jQuery plugin code, you can change mine to work with words.Questions, remarks, bugs found are welcome 😉 I tested it in IE9, FF3.6, Chrome 9
UPDATE: Accroding to an issue with
<li>, <h1>… E.g. I have container with content:In this case browser behaves this way (string by string what is in container and what I see it shows according to the algorithm):
and result of algorithm is string
"<strong><i>Strong text with <u</i></strong>"– with"<u", what is not nice. What I need to process in this case is that if we found our result string ("<strong><i>Strong text with <u"according to the algorithm), we need to removed last “unclosed” tag ("<u"in our case), so before closing tags to have valid html I added the following:probably a bit lazy implementation, but it can be tuned if it slows down. What is done here
>(in our case it returns["<strong", "<i", "<u"]);"<u")croppedTextstring, then we remove itafter doing it, the result string becomes
"<strong><i>Strong text with </i></strong>"UPDATE2 thank you for example, so I see that you don’t have just nested tags, but they also have “tree” structure, indeed I didn’t take it into account, but it still can be fixed 😉 At the beginning I wanted to write my appropriate “parser”, but all the time I get an example when I does not work, so I thought it is better to find already written parser, and there is one: Pure JavaScript HTML Parser. There is also one shag to it:
but for your example it works; that library didn’t take into account position of opening tag, but
I think that with that assumptions this library is nice to use. Then result function looks like: