How to limit a <td> to only three lines? - javascript

I would like to achieve a unified look and feel across all my table rows.
When you look at my example below you can see that the note in the middle goes over 4 lines and thats not so pretty.
I was hoping to limit all <td> to 3 lines.
If there is more to be shown than three lines, then it should cut the content with ... [click for more] and put the content inside a collapseable element, so that when clicked on it it would show the whole content.
The latter shouldn't be a problem, but how do I limit the content to only three lines? Shall I count the characters to make the decision upon that? Is there a better strategy? I am using Django by the way,but I am happy to use javascript, jquery or any css magic instead to solve this.
Update:
The accepted answer is very good. However it comes with a caveat, which isn't easy to solve.
if you have a neighbouring td that already goes over three lines, while the current td is only two lines we will get an infinite while loop.
while($(this).innerHeight() / $(this).css('line-height').slice(0,-2) >= 3){ .. }
Since $(this).innerHeight() can't decrease because of the neighbouring cell holding the height up high. I think if it was possible to get the css of the current td and copy it across the content completely in a separate field, where neighbouring tds can't interfere, we would get the optimal solution.
Update 2:
As Assad mentioned, the solution is to put a div wrapper around the content of td and set the class on the div inside the td rather than on the td itself. It works flawlessly.

Assuming you are using jQuery, you could find all td elements that exceed a certain number of lines using:
$('td').filter(function(){
return $(this).innerHeight() / $(this).css('line-height').slice(0,-2) > 3; //more than 3 lines
});
You could then apply collapsible elements to these td elements.
Here is a demonstration (using paragraphs instead of tds): http://jsfiddle.net/jM4ZY/1/
Here is an example of cutting off content to fit 3 lines, then adding a more button: http://jsfiddle.net/jM4ZY/2/
As far as the edit is concerned, this is easily resolved by using an inner wrapper for your content; possibly a div element. You can then measure the height of this element, which is independent of the height of neighboring cells.

Another jQuery solution is described here
It is described how to change the Text by counting the number of letters in the displayed text. If you are unsure about the number of letters, or want to make it dependent of the text-length you can calculate it by using this snipped
$.fn.textWidth = function(){
var html_org = $(this).html();
var html_calc = '<span>' + html_org + '</span>';
$(this).html(html_calc);
var width = $(this).find('span:first').width();
$(this).html(html_org);
return width;
};
which I took from Calculating text width

Related

Creating a Page Break in HTML

I am creating a resume using html and some elements have multiple lines. For example, an education can have the institute, the date attended, and the degree received on separate lines. However, the institute, the date, and the degree are all part of one record.
I am trying to create a page break when I print using html. I only want the page break to be inserted if the number of lines in the next element is greater than the number of lines remaining on the 8.5 x 11 page. Using the example earlier, I want all of the lines in the education record all on one page. The data is being passed in, so the page breaks can vary from resume to resume.
I have found code to create the page break: #media print {footer {page-break-after: always;}}.
I have also found code that can get the line height of a div:
var element = document.getElementById('content');
document.defaultView.getComputedStyle(element,null).getPropertyValue("lineHeight");
I need to count the number of lines remaining on the 8x11 page and compare that height to the height of the next element. Instead of using page breaks, another option would be to just add enough empty lines to move the element down enough for it to be all on one page, but I still need to be able to count the remaining lines. I would appreciate any suggestions. Thanks.
EDIT: Here is my code so far:
var totalHeight = 1056;
var divHeight = document.getElementById('element').offsetHeight;
totalHeight = totalHeight - divHeight;
if(totalHeight < 0)
{
document.write("<style>");
document.write("#media print {#element {page-break-after: always;}}");
document.write("</style>");
}
However, when I print out the total height it only returns a number slightly over 200. Instead, the number should exceed 1056. Does the offsetHeight method only return the size of the text itself and not the spacing around it or is there another problem that could be causing the drastic difference? Thanks.
I think the trickiest part here is dealing with whatever margin the browser will put on the page when it goes to print. Not sure if you can control that. But if you can, try using in as your sizing unit instead of something like px or em. Then, if you calculate that you're going to go over 11in with what you've got, add your page break.
Here's a pseudo-code algorithm:
var totalHeight = page margin
foreach div:
totalHeight += calculated height in inches
if totalHeight > 11in:
insert page break
rinse and repeat for further pages

Break UL into multiple columns

It is difficult to extract code and post it here, so I'm posting a sample site which demonstrates my problem. I've been thinking about this, and there are several ways to solve this problem (HTML modification, CSS + HTML modification, CSS + JS modification), but since I'm a n00b at web coding, I want to know what is the best plan of attack here.
Anyways, the problem:
Have a look here: http://321cart.com/sellya/
Open the Categories Navigation menu, and you get this:
All those links under the categories are ul containing lots of li. I want to break the list and spread the list of multiple columns, so that there are only a maximum of 3 li in one column. Here is an example of what I want to do:
This is the overall thing that I want:
This will cause the menu width to increase (virtually double, in theory), but that is okay for me. I can deal with this on my own.
There are several methods to do this, but I would prefer if there's some way to do this using only CSS modification. If not, then maybe through CSS and JavaScript modification ? I want to reserve changes to actual HTML code as a last resort, because that is the original PHP HTML generation OpenCart code which I don't want to modify.
Please note that I did try to resolve this problem on my own, but it proved to be a little complex .. So don't think I didn't try .. Secondly, posting this in a JSFiddle would have been difficult to, and it would not have truly represented the actual problem fully, which is why I'm posting a link to a sample site.
Please have a look guys. Site: http://321cart.com/sellya/
So I need some answers for this problem that has me baffled.
EDIT:
Forgot to point this out. In the example I provided, all uls had more than 3 lis each, but in my actual case, only a few uls have more than 3 lis each, and I only want to extend those ones to 2 columns, not the ones will 1, 2 or 3 lis each.
CSS3 introduced columns, which should do what you want. In theory, simply apply a height and column-width to your ul. In practice, you might need to use vendor prefixes on the column-width, giving you -webkit-column-width, -moz-column-width, etc. Try it out.
You can set the outer divs width (the ones with "span2" class in the provided link) to something like 350px and set LIs width to 100px and float:left directive. This is the simplest approach you can use.
take a look at this:
var $columns = $("#columns");
var $longlist = $("#longlist");
var columnscount = 3;
//calculate sigle column size
var columnsize = Math.ceil($("p", $longlist).size() / columnscount);
//iterate number of columns, take [columnsize] elements, move them to div#columns and wrap with div.column
for (var i = 0; i < columnscount; i++) {
$("p:lt(" + columnsize + ")", $longlist).appendTo($columns).wrapAll("<div class='column'/>")
}
you would need to add some condition to avoid spliting list shorter that 3 elements.
and this is how it works:
http://jsfiddle.net/hGWjd/

Make table cells responsive and make them evenly square, filling the window

I want to make table cells responsive - even squares filling all available space(window).
If table width is 100% - it takes all available space, distributing cells evenly but only horizontally. I have written small javascript with jquery, calling this function on window resize event:
function windowReszie(){
$("td").each(function(){
$(this).css({"height":$(this).width()});
})
}
But this approach is slow, because I have a lot of cells - is there a way to do it just with css or any other better , faster way?
I see some problem with your approach, you're computing the width for every cell.
I'd do something along the lines of
function windowReszie(){
var size =$("td").width();
$("td").height(size);
}
Another approach would be to set a class and change the css rule associated with the class, but that could be a bit tricky (see : Changing a CSS rule-set from Javascript)
try adding class only at first <td> in <tr> and then loop over that class... no need to check every <td> item.

Two columns text block with an image

I need some help...
How should I do the markup of a layout with two images and a block of text divided in 2 columns with different width, where the 2nd column starts lower than the first one because of one of those images? Here is a sketch of my layout:
I hope I described my problem explicitly enough.
P.S.: Is it possible actually?
CSS3 has a solution, but it is not standard yet and won't work in older browsers here is a link http://www.css3.info/preview/multi-column-layout/.
Possibly the best idea is to use javascript somehow. Put all the text in the first column and test the height then move portions of the text over to the next column until you have equal columns or until the first column is at a desired height.
Another method is to have predefined proportions eg(2/3 in the first column and 1/3 in the second). Then split the text based on the proportions using character count. This won't be exact and you could use a method similar to the one above to find exact width based on overflow properties, but the characters should average out to be the correct length.
This method is pretty simple and would look like
var txt='Column text...';
var len=txt.length;
var chars=Math.floor(len*.67);
//Assuming you want 2/3 of the text in the first column
document.getElementById('col1').innerHTML=txt.substring(0,chars);
document.getElementById('col2').innerHTML=txt.substring(chars);
//Notice that this could split in the middle of a word so you would need to do
//some checking for the nearest space and the change the break to there.
//Also you could then use the previous method to adjust it if you want something really accurate

Copy half of an HTML child nodes array

I have an HTML element (let's say a division) that contains a set titles (h2) and paragraphs (p) with other element inside (some links for example, a).
My goal is to cut my HTML element in 2 same size element.
Constrains : paragraphs, titles, and block should not be cut
My idea asbout this was to browse inside the child nodes list and copy childNodes of each paragraphs.
Each time I copy a paragraph, i compute the size in ordre to know if I reached the half size of the division.
Here is some code to explain it:
var elm = document.getElementById('article_colonnes'); // I want to cut this into 2 parts
var paragraphesNumber = paragraphes.length;
var halfSize = elm.innerHTML.length / 2 ;
var col1 = document.getElementById('col1');
var col2 = document.getElementById('col2');
var i=0;
do {
var node = createNodeFromParagraphe(paragraphes[i]);
if(node) {
col1.appendChild(node);
// update the size of the 1st column by updating inner HTML
col1String = col1String + paragraphes[i].innerHTML;
}
i++;
// compute the size of the 1st column
col1Size = col1String.length;
}
while(col1Size < halfSize || i < paragraphesNumber) ;
And I do the same for the 2nd column.
Thanks for your help.
If your trying to make an automatic two column layout; take a look at multicolumnlists
To get a true two column layout, you need the height of the paragraphs (not the characters in it). The problem here: The only way to get the height is to wait for the browser to layout the page unless you specify the width of every element. Otherwise, the user would see an ugly flicker.
So I suggest to try this:
Use a multi column layout which most browser support. If the browser is not IE <= 7, you're done.
For IE 7 and lower, set a fixed width for all elements. Wait for the browser to layout the page (it should be enough to run this code in body.onload or from a script tag at the end of the page). Put all elements into a div with the id "col1".
Use JavaScript to find the element at half the height of the the div "col1". (see here)
If this element is a heading, skip one element.
Move the next element (and all beyond) into the div "col2".
That should give you a longer col1 and a shorter col2.
If moving doesn't work, insert an invisible character after you identified the split point, get col1.innerHtml, split it at the split char and use the resulting two strings as innerHtml for col1 and col2.
If that flickers a lot, try to hide col1 and col2 while your script runs (display='None').

Categories

Resources