I have a table containing decimal numbers in one column. I'm looking to align them in a manner similar to a word processor's "decimal tab" feature, so that all the points sit on a vertical line.
I have two possible solutions at the moment but I'm hoping for something better...
Solution 1: Split the numbers within the HTML, e.g.
<td><div>1234</div><div class='dp'>.5</div></td>
with
.dp { width: 3em; }
(Yes, this solution doesn't quite work as-is. The concept is, however, valid.)
Solution 2: I found mention of
<col align="char" char=".">
This is part of HTML4 according to the reference page, but it doesn't work in FF3.5, Safari 4 or IE7, which are the browsers I have to hand. It also has the problem that you can't pull out the numeric formatting to CSS (although, since it's affecting a whole column, I suppose that's not too surprising).
Thus, anyone have a better idea?
See this article by Krijn Hoetmer for your options and how to achieve this. The essence of this solution is to use CSS and JS to achieve this:
(function() {
var currencies = /(\$|€|€)/;
var leftWidth = 0, rightWidth = 0;
for(var tableCounter = 0, tables = document.getElementsByTagName("table");
tableCounter < tables.length; tableCounter++) {
if(tables[tableCounter].className.indexOf("fix-align-char") != -1) {
var fCols = [], leftPart, rightPart, parts;
for(var i = 0, cols = tables[tableCounter].getElementsByTagName("col"); i < cols.length; i++) {
if(cols[i].getAttribute("char")) {
fCols[i] = cols[i].getAttribute("char");
}
}
for(var i = 0, trs = tables[tableCounter].rows; i < trs.length; i++) {
for(var j = 0, tds = trs[i].getElementsByTagName("td"); j < tds.length; j++) {
if(fCols[j]) {
if(tds[j].innerHTML.indexOf(fCols[j]) != -1) {
parts = tds[j].innerHTML.split(fCols[j]);
leftPart = parts.slice(0, parts.length -1).join(fCols[j]);
leftPart = leftPart.replace(currencies, "<span class='currency'>$1</span>");
rightPart = fCols[j] + parts.pop();
tds[j].innerHTML = "<span class='left'>" + leftPart + "</span><span class='right'>" + rightPart + "</span>";
} else {
tds[j].innerHTML = tds[j].innerHTML.replace(currencies, "<span class='currency'>$1</span>");
tds[j].innerHTML = "<span class='left'>" + tds[j].innerHTML + "</span>";
}
tds[j].className = "char-align";
var txt = document.createTextNode(tds[j].firstChild.offsetWidth);
if(leftWidth < tds[j].firstChild.offsetWidth) {
leftWidth = tds[j].firstChild.offsetWidth;
}
if(tds[j].childNodes[1]) {
txt = document.createTextNode(tds[j].childNodes[1].offsetWidth);
if(rightWidth < tds[j].childNodes[1].offsetWidth) {
rightWidth = tds[j].childNodes[1].offsetWidth;
}
}
}
}
}
}
}
// This is ugly and should be improved (amongst other parts of the code ;)
var styleText = "\n" +
"<style type='text/css'>\n" +
" .fix-align-char td.char-align { width: " + (leftWidth + rightWidth) + "px; }\n" +
" .fix-align-char span.left { float: left; text-align: right; width: " + leftWidth + "px; }\n" +
" .fix-align-char span.currency { text-align: left; float: left; }\n" +
" .fix-align-char span.right { float: right; text-align: left; width: " + rightWidth + "px; }\n" +
"</style>\n";
document.body.innerHTML += styleText;
})();
table {
border-collapse: collapse;
width: 600px;
}
th {
padding: .5em;
background: #eee;
text-align: left;
}
td {
padding: .5em;
}
#only-css td.char-align {
width: 7em;
}
#only-css span.left {
float: left;
width: 4em;
text-align: right;
}
#only-css span.currency {
float: left;
width: 2em;
text-align: left;
}
#only-css span.right {
float: right;
width: 3em;
text-align: left;
}
<table id="only-css">
<thead>
<tr>
<th>Number</th>
<th>Description</th>
<th>Costs</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Lorem ipsum dolor sit amet</td>
<td class="char-align">
<span class="left">
<span class="currency">$</span>3
</span>
<span class="right">,99</span>
</td>
</tr>
<tr>
<td>2</td>
<td>Consectetuer adipiscing elit</td>
<td class="char-align">
<span class="left">
<span class="currency">$</span>13
</span>
<span class="right">,95</span>
</td>
</tr>
<tr>
<td>3</td>
<td>Pellentesque fringilla nisl ac mi</td>
<td class="char-align">
<span class="left">
<span class="currency">$</span>4
</span>
<span class="right"></span>
</td>
</tr>
<tr>
<td>4</td>
<td>Aenean egestas gravida magna</td>
<td class="char-align">
<span class="left">
<span class="currency">$</span>123
</span>
<span class="right">,999</span>
</td>
</tr>
</tbody>
</table>
Another way to format a number would be like this: 35<span style="visibility: hidden">.000</span>. That is, write it out with the full decimal expansion, but write the trailing decimals in invisible ink. That way you don't have to worry about the width of the decimal point.
I'm surprised that in 10 years of answers to this question, nobody ever mentioned the Unicode character 'FIGURE SPACE' (U+2007, )
It's a whitespace character that is designed (by font authors, if they follow the standard) to be the same width as digits and to keep its spacing, like its more famous cousin the No-Break Space. You can use it to pad numbers to a certain string size, either on the left or on the right hand side, taking care of aligning the column or div on the same side.
Examples, both left-aligned and left-padded with figure spaces:
<p style="font-family: sans-serif">
10000 <br>
123.4 <br>
3.141592
</p>
<p style="font-family: serif">
10000 <br>
123.4 <br>
3.141592
</p>
Cheat; benefit of this solution: also works for proportional fonts. Have one extra column and split the integer part from the decimal separator and the decimals. Then use this css and combine two columns in the header row:
table {border-collapse:collapse;}
td {padding:0px;margin:0px;border:0px;}
td+td {text-align:right;}
td, td+td+td {text-align:left;}
<table>
<tr><th>Name</th><th colspan=2>Height</th></tr>
<tr><td>eiffeltower</td> <td>324</td> <td></td></tr>
<tr><td>giraffe</td> <td>5</td> <td>,30</td></tr>
<tr><td>deer</td> <td>1</td> <td></td></tr>
<tr><td>mouse</td> <td>0</td> <td>,03</td></tr>
</table>
Caveat: It isn't guaranteed to work. For example, on Safari 14 in 2021:
I played around with jQuery & came up with this...
$(document).ready(function() {
$('.aBDP').each(function() {
var wholePart, fractionPart;
wholePart = Math.floor($(this).text()-0);
fractionPart = Math.floor(($(this).text() % 1)*10000 + 0.5) / 10000 + "";
html = '<span class="left">' + wholePart + '.' + '</span>';
html += '<span class="right">' + fractionPart.substring(2) + '</span>';
$(this).html(html);
})
})
.right {
text-align: left;
}
.left {
float:left;
text-align: right;
width:10em;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js" type="text/javascript"></script>
<table width="600" border="1">
<tr><th></th><th>Aligned Column</th></tr>
<tr><th>1st Row</th><td class='aBDP'>1.1</td></tr>
<tr><th>2nd Row</th><td class='aBDP'>10.01</td></tr>
<tr><th>3rd Row</th><td class='aBDP'>100.001</td></tr>
<tr><th>4th Row</th><td class='aBDP'>1000.0001</td></tr>
</table>
It seemed to work.
can you just print the numbers so that they always have the same number of decimal places, and right align them?
Thousands of years ago (or 2-3) I wrote a jQuery shim that emulates align="char" which still seems to work. It uses CSS padding and accounts for colspans, so it's moderately clever, but it's really not very pretty code (I was just starting out in javascript back then). I'd love for someone to rewrite it (and take all the credit).
In the mean time, see if this helps you: https://gist.github.com/mattattui/f27ffd25c174e9d8a0907455395d147d
Trivia: The reason that browsers don't properly support column styles is that tables are 2D data structures and the DOM (which is what Javascript and CSS operate on, and how HTML5 is defined) is purely hierarchical and therefore can't represent both columns and rows. Instead it simply defines rows and cells, and doesn't represent columns at all.
I love short answers, even though the long ones are important too, so I liked;
35<span style="color:transparent">.000</span>
and would just like to add;
<TD><div style='float:right;'><?php echo number_format($totalAmount,2); ?></div></TD>
just to throw php into the mix. Much depends on fixed width fonts, still, but the latter works for me. Since data oft is already tabular, adding another table within a cell is just too much typing and hard to maintain.
If the numbers are monospaced, javascript could be used to adjust the padding on the cell (in ems), depending on the number of digits before the decimal point. Otherwise, it could be tricky.
The function made by Krijn Hoetmer interferes with prettyPhoto ( http://www.no-margin-for-errors.com/projects/prettyphoto-jquery-lightbox-clone/ ) so I made a jQuery version. The currency part is removed as it should be made dynamic instead of replacing strings based on predefined currencies.
Needed is the empty function from phpjs: http://phpjs.org/functions/empty:392 .
The jQuery used, is version 1.6.
/* This function will align table columns on the char if in the col from the
* colgroup has the property 'align="char"' and a attribute 'char'. The alignment
* is done on the first occurence of the specified char.
*
* The function is inspired from:
*
* http://krijnhoetmer.nl/stuff/javascript/table-align-char/
* http://stackoverflow.com/questions/1363239/aligning-decimal-points-in-html
*/
function alignNumbers()
{
var table; /* This will store the table currently working on . */
var i = 0; /* Every column can have it's own width, the counter makes the class name unique. */
/* Get all tables for which the alignment fix must be done.
*
* Note: this could even be further optimized by just looking for tables where
* there is a a col with 'align="char"'.
*/
$('table.fix-align-char').each(function(index)
{
table = $(this);
/* All table columns are fetched to have a correct index, without it it's
* hard to get the correct table cells.
*/
$(this).find('col').each(function(index)
{
/* Only those table cells are changed for which the alignment is set to
* char and a char is given.
*/
if ($(this).prop('align') == 'char' && !empty($(this).attr('char')))
{
/* Variables for storing the width for the left and right part (in pixels). */
var left_width = 0, right_width = 0;
var col, left_part, right_part, parts, new_html;
i++; /* Increase the counter since we are working on a new column. */
col = $(this);
/* For the col index + 1 (nth-child starts counting at 1), find the table
* cells in the current table.
*/
table.find('> tbody > tr > td:nth-child('+ (index + 1) +')').each(function(index)
{
/* Split the html on the specified char. */
parts = $(this).html().split(col.attr('char'));
new_html = '';
/* The first element is always the left part. The remaining part(s) are
* the right part. Should there be more chars in the string, the right
* parts are rejoined again with the specified char.
*/
left_part = parts.shift();
right_part = parts.join(',');
/* Add a left part to the new html if the left part isn't empty*/
if (!empty(left_part))
{
new_html = new_html + '<span class="left">' + left_part + '</span>';
}
/* Add the specified char and the right part to the new html if
* the right part isn't empty*/
if (!empty(right_part))
{
new_html = new_html + col.attr('char') + '<span class="right">' + right_part + '</span>';
}
/* If there is a new html, the width must be determined and a class is
* added.
*
* Note: outerWidth is used instead of width so padding, margin and
* borders are taken into account.
*/
if (!empty(new_html))
{
$(this).html(new_html); /* Set the new html. */
$(this).addClass('char-align-' + i); /* Add a class to the table cell. */
/* Get the left span to determine its outer width. */
leftSpan = $(this).children('.left');
if (!empty(leftSpan) && left_width < leftSpan.outerWidth())
{
left_width = leftSpan.outerWidth();
}
/* Get the right span to determine its outer width. */
rightSpan = $(this).children('.right');
if (!empty(rightSpan) && right_width < rightSpan.outerWidth())
{
right_width = rightSpan.outerWidth();
}
}
});
/* Only if any width is larger then 0, add a style. */
if (left_width > 0 || right_width > 0)
{
style_text = '<style type="text/css">.fix-align-char td.char-align-' + (i) + ' span.left { float: left; text-align: right; width: ' + (left_width) + 'px; }\n.fix-align-char td.char-align-' + (i) + ' span.right { float: right; text-align: left; width: ' + right_width + 'px; }</style>';
$('head').append(style_text);
}
}
});
});
}
$(document).ready(function(){
alignNumbers();
});
I have used JavaScript to fix this issue...
This is my HTML.
<body>
<table id="nadis">
</tr>
</table>
</body>
This is my JavaScript.
var numarray = ["1.1", "12.20", "151.12", 1000.23,12451];
var highetlen = 0;
for(var i=0; i<numarray.length; i++){
var n = numarray[i].toString();
var res= n.split(".");
n = res[0];
if(highetlen < n.length){
highetlen = n.length;
}
}
for(var j=0; j<numarray.length; j++){
var s = numarray[j].toString();
var res= s.split(".");
s = res[0];
if(highetlen > s.length){
var finallevel = highetlen - s.length;
var finalhigh = "";
for(k=0;k<finallevel;k++){
finalhigh = finalhigh+ ' ';
}
numarray[j] = finalhigh + numarray[j];
}
var nadiss = document.getElementById("nadis");
nadiss.innerHTML += "<tr><td>" + numarray[j] + "</td></tr>";
}
A serious trouble in the previous approaches, is that only think in visual, but do not in other needs or uses of tables as sorting or filtering, where pure data is important.
Unfortunately CSS4 are not available yet. Then a valid solution could be pass the value and units or type unit in data attributes on td cell.
<!-- HTML-->
<table>
<tbody>
<tr>
<td data-value="1876.67542" data-unit="USD"></td>
</tr>
</tbody>
</table>
If a cell have a data value, it must read with javascript and updated to the decimal numbers that we requires.
// Javascript
let $td_value = document.querySelectorAll( 'td[data-item]' );
Array.from( $td_value ).forEach( $r => {
$r.textContent = parseFloat( $r.getAttribute('data-value') ).toFixed(2);
});
At the end, when we have normalized data, they will looks great with mono fonts and with their units placed using css selectors as before or after.
/* CSS */
td[data-value]{
font-family: monospace;
text-align: right;
}
td[data-unit]::after{
content: attr(data-unit]);
font-size: 85%;
padding-left: .2em;
opacity: .6;
}
I put an extended example in: https://jsfiddle.net/jam65st/wbo63xpu/12/
Ugly workaround but will save you from writing a lot of code:
You can find the max number in the array (list) of prices, then you can take the number of its digits and set inline style "width": (maxNumberDigits * 10)px - this is the ugly part!
And the container of this data (cell if its table) should have additionally
display:flex;
justify-content: flex-end;
Result:
Related
As we all know inline styles are not good practice and they are not compatible with e.g. the Content Security Policy.
This is what I want to achieve without inline styles:
<?php
$spacer_height = 390; // this is a dynamic value from user input could be any integer
?>
<div class="spacer" style="height:<?php echo $spacer_height; ?>"></div>
This is what I want:
HTML:
<?php
$spacer_height = 390; // this is a dynamic value from user input
?>
<div class="spacer spacerheight-<?php echo $spacer_height; ?>" data-height="<?php echo $spacer_height; ?>"></div>
External Stylesheet:
.spacer {
height: spacer_height + "px"; // this line is dummy code
}
Is where a way to achieve this with CSS only. No JavaScript. No Polyfill.
What I have already found is this 5 year old question: CSS values using HTML5 data attribute
However is there a solution meanwhile or is there a CSS solution not using attributes? Is there at least a solution for integers?
Edit: Even a working polyfill may be a welcome answer if there is no other solution.
As you can't do this CSS only (yet, since the attr() function only returns string value), here is a simple script that will do something similar what attr() does, though this parse the data and sets it dynamically using cssText.
Let me know if I got this right
window.addEventListener("load", function() {
var mb = isMobile();
var el = document.querySelectorAll('[data-css]');
for (i = 0; i < el.length; i++) {
var what = el[i].getAttribute('data-css');
if (what) {
what = what.split(',');
el[i].style.cssText = what[0] + ': ' + ((mb) ? what[2] : what[1]) + 'px';
}
}
});
function isMobile() {
//function that check if user is on mobile etc.
return false; // return false for this demo
}
html, body {
margin: 0;
}
div {
background-color: lightgreen;
padding: 10px 0;
height: auto;
box-sizing: border-box;
}
div ~ div {
margin-top: 10px;
}
<div data-css="height,60,30"></div>
<div></div>
<div></div>
<div data-css="height,60,30"></div>
<div></div>
Another option would be to run something server side, where you simply create the CSS rule and class and insert it into CSS file and markup respectively, before sending to the client
You might consider moving the dynamic part from being inline to being referenced in a <style>.
<style>
.spacer {
height:<?php echo $spacer_height; ?>
}
</style>
<?php
$spacer_height = 390; // this is a dynamic value from user input could be any integer
?>
<div class="spacer"></div>
I have a list of paths (for lack of a better word, maybe bread crumb trails describes them better). Some of the values are too long to display in their parent so I'm using text-overflow: ellipsis. The problem is that the important information is on the right, so I'd like the ellipsis to appear on the left. Something like this this ascii art:
----------------------------
|first > second > third |
|...second > third > fourth|
|...fifth > sixth > seventh|
----------------------------
Notice that the first row is short enough so it remains left aligned, but the other two are too long so the ellipsis appears on the left hand side.
I'd prefer a CSS only solution, but JS is fine if it can't be avoided. It's ok if the solution only works in Firefox and Chrome.
EDIT: At this point I'm looking for a work around for the bugs in Chrome that prevent it from rendering properly when a document is mixed RTL and LTR. That was all I really needed from the outset, I just didn't realize it.
How about something like this jsFiddle? It uses the direction, text-align, and text-overflow to get the ellipsis on the left. According to MDN, there may be the possibility of specifying the ellipsis on the left in the future with the left-overflow-type value however it's considered to still be experimental.
p {
white-space: nowrap;
overflow: hidden;
/* "overflow" value must be different from "visible" */
text-overflow: ellipsis;
width: 170px;
border: 1px solid #999;
direction: rtl;
text-align: left;
}
<p>first > second > third<br /> second > third > fourth > fifth > sixth<br /> fifth > sixth > seventh > eighth > ninth</p>
I finally had to crack and do something in JavaScript. I was hoping that someone would come up with a hail-mary CSS solution but people seem to just be up-voting the answer that should be correct if it weren't for the Chrome bugs. j08691 can have the bounty for his work.
<html>
<head>
<style>
#container {
width: 200px;
border: 1px solid blue;
}
#container div {
width: 100%;
overflow: hidden;
white-space: nowrap;
}
</style>
<script>
function trimRows() {
var rows = document.getElementById('container').childNodes;
for (var i=0, row; row = rows[i]; i++) {
if (row.scrollWidth > row.offsetWidth) {
var textNode = row.firstChild;
var value = '...' + textNode.nodeValue;
do {
value = '...' + value.substr(4);
textNode.nodeValue = value;
} while (row.scrollWidth > row.offsetWidth);
}
}
}
</script>
</head>
<body onload='trimRows();'>
<div id="container" >
<div>first > second > third</div>
<div>second > third > fourth > fifth > sixth</div>
<div>fifth > sixth > seventh > eighth > ninth</div>
</div>
</body>
</html>
Fiddle
Why not just using direction:rtl;
It's a little buggy, but maybe a point in the right direction
http://jsfiddle.net/HerrSerker/ZfbaD/50/
$('.container')
.animate({'width': 450}, 4000)
.animate({'width': 100}, 4000)
.animate({'width': 170}, 4000)
.container {
white-space: nowrap;
overflow: hidden; /* "overflow" value must be different from "visible" */
text-overflow: ellipsis;
width:170px;
border:1px solid #999;
direction:rtl;
}
.container .part {
direction:ltr;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<span class="part">second</span>
<span class="part">></span>
<span class="part">third</span>
<span class="part">></span>
<span class="part">fourth</span>
<span class="part">></span>
<span class="part">fifth</span>
<span class="part">></span>
<span class="part">sixth</span>
</div>
These solutions solve the problem with misinterpreted preceding or trailing weak or neutral BiDi characters such as /, \, ~, ., etc. (basically any punctuation or special characters).
CSS Solution
Use a combination of:
direction: rtl & ltr
unicode-bidi: bidi-override
p {
direction: rtl;
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; /* or pre (e.g. preserve multiple spaces) */
}
span {
direction: ltr;
unicode-bidi: bidi-override; /* or isolate, isolate-override, embed */
}
<p><span>/path/to/a/very/long/file.name</span></p>
<bdo> Solution
Another possibility uses the <bdo> Bidirectional Text Override element:
p {
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; /* or pre (e.g. preserve multiple spaces) */
}
<bdo dir="rtl">
<p>
<bdo dir="ltr">/path/to/a/very/long/file.name</bdo>
</p>
</bdo>
Using #Hemlocks, #Brian Mortenson and #Jimbo's solutions, I've built a jQuery plugin to solve this problem.
I've also added support to return the initial value using .html() rather than having it return the current innerHTML. Hopefully it will be useful to someone...
(function($) {
$.trimLeft = function(element, options) {
var trim = this;
var $element = $(element), // reference to the jQuery version of DOM element
element = element; // reference to the actual DOM element
var initialText = element.innerHTML;
trim.init = function() {
overrideNodeMethod("html", function(){ return initialText; });
trimContents(element, element);
return trim;
};
trim.reset = function(){
element.innerHTML = initialText;
return trim;
};
//Overide .html() to return initialText.
var overrideNodeMethod = function(methodName, action) {
var originalVal = $.fn[methodName];
var thisNode = $element;
$.fn[methodName] = function() {
if (this[0]==thisNode[0]) {
return action.apply(this, arguments);
} else {
return originalVal.apply(this, arguments);
}
};
};
var trimContents = function(row, node){
while (row.scrollWidth > row.offsetWidth) {
var childNode = node.firstChild;
if (!childNode)
return true;
if (childNode.nodeType == document.TEXT_NODE){
trimText(row, node, childNode);
}
else {
var empty = trimContents(row, childNode);
if (empty){
node.removeChild(childNode);
}
}
};
};
var trimText = function(row, node, textNode){
var value = '\u2026' + textNode.nodeValue;
do {
value = '\u2026' + value.substr(4);
textNode.nodeValue = value;
if (value == '\u2026'){
node.removeChild(textNode);
return;
}
}
while (row.scrollWidth > row.offsetWidth);
};
trim.init();
};
$.fn.trimLeft = (function(options){
var othat = this;
var single = function(that){
if (undefined == $(that).data('trim')) {
var trim = new $.trimLeft(that, options);
$(that).data('trim', trim);
$(window).resize(function(){
$(that).each(function(){
trim.reset().init();
});
});
}
};
var multiple = function(){
$(othat).each(function() {
single(this);
});
};
if($(othat).length>1)
multiple(othat);
else
single(othat);
//-----------
return this;
});
})(jQuery);
Initiate using:
//Call on elements with overflow: hidden and white-space: nowrap
$('#container>div').trimLeft();
//Returns the original innerHTML
console.log($('#test').html());
fiddle
Using a slightly more complex markup (using the bdi-tag and an extra span for the ellipsis), we can solve the problem fully in CSS, no JS required at all -- cross browser (IE, FF, Chrome) and including keeping punctuation marks to the right:
http://jsbin.com/dodijuwebe/1/edit?html,css,output
Granted, this is something of a hack, involving pseudo-element goodness. However, our team has been using this code in production and we haven't had any issues whatsoever.
The only caveats are: The height of the line needs to be fixed and the background color needs to be known explicitly (inherit won't work).
If you don't care the indexing of those texts, you could use this method (it reverses the text lines):
If you have in your texts other HTML elements besides <br> you need to make some arrangements to use this method.
HTML code:
<p>first > second > third<br/>
second > third > fourth <br>
fifth > sixth > seventh</p>
CSS code:
p{
overflow: hidden;
text-overflow: ellipsis;
unicode-bidi: bidi-override;
direction: rtl;
text-align: left;
white-space: nowrap;
width: 140px;
}
JavaScript code
[].forEach.call(document.getElementsByTagName("p"), function(item) {
var str = item.innerText;
//Change the operators
str = str.replace(/[<>]/g, function(char){ return ({"<" : ">", ">" : "<"})[char] });
//Get lines
var lines = str.split(/\n/);
//Reverse the lines
lines = lines.map(function(l){ return l.split("").reverse().join("") });
//Join the lines
str = lines.join("<br>");
item.innerHTML = str;
});
jsfiddle
Based on your edit:
At this point I'm looking for a work around for the bugs in Chrome
that prevent it from rendering properly when a document is mixed RTL
and LTR. That was all I really needed from the outset, I just didn't
realize it.
Have you looked into the unicode-bidi css property (see Sitepoint or W3C)? I actually just learned about this myself on another recent post. My guess is you would want to use the embed value for those pieces going the opposite direction to the main site. So in j08691's answer where it is direction: rtl add unicode-bidi: embed to the CSS. This should solve "mixed RTL and LTR" issues you are having.
I put some JavaScript together to regex out three items and add the ellipsis in where necessary. This does not explicitly look at how much text will fit in the box but if the box is fixed this may not be an issue.
<style>
p {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width:170px;
border:1px solid #999;
direction:rtl;
text-align:left;
}
</style>
<p>first > second > third<br />
second > third > fourth > fifth > sixth<br />
fifth < sixth < seventh < eighth < ninth</p>
<script>
var text = $( 'p' ).text(),
split = text.split( '\n' ),
finalStr = '';
for( i in split ){
finalStr = finalStr.length > 0 ? finalStr + '<br />' : finalStr;
var match = /(\w+\s?(<|>)?\s?){3}$/.exec( split[i] );
finalStr = finalStr + ( split[i].length > match[0].length ? '...' : '' ) + match[0];
}
$( 'p' ).empty().html( finalStr );
</script>
I have a table containing decimal numbers in one column. I'm looking to align them in a manner similar to a word processor's "decimal tab" feature, so that all the points sit on a vertical line.
I have two possible solutions at the moment but I'm hoping for something better...
Solution 1: Split the numbers within the HTML, e.g.
<td><div>1234</div><div class='dp'>.5</div></td>
with
.dp { width: 3em; }
(Yes, this solution doesn't quite work as-is. The concept is, however, valid.)
Solution 2: I found mention of
<col align="char" char=".">
This is part of HTML4 according to the reference page, but it doesn't work in FF3.5, Safari 4 or IE7, which are the browsers I have to hand. It also has the problem that you can't pull out the numeric formatting to CSS (although, since it's affecting a whole column, I suppose that's not too surprising).
Thus, anyone have a better idea?
See this article by Krijn Hoetmer for your options and how to achieve this. The essence of this solution is to use CSS and JS to achieve this:
(function() {
var currencies = /(\$|€|€)/;
var leftWidth = 0, rightWidth = 0;
for(var tableCounter = 0, tables = document.getElementsByTagName("table");
tableCounter < tables.length; tableCounter++) {
if(tables[tableCounter].className.indexOf("fix-align-char") != -1) {
var fCols = [], leftPart, rightPart, parts;
for(var i = 0, cols = tables[tableCounter].getElementsByTagName("col"); i < cols.length; i++) {
if(cols[i].getAttribute("char")) {
fCols[i] = cols[i].getAttribute("char");
}
}
for(var i = 0, trs = tables[tableCounter].rows; i < trs.length; i++) {
for(var j = 0, tds = trs[i].getElementsByTagName("td"); j < tds.length; j++) {
if(fCols[j]) {
if(tds[j].innerHTML.indexOf(fCols[j]) != -1) {
parts = tds[j].innerHTML.split(fCols[j]);
leftPart = parts.slice(0, parts.length -1).join(fCols[j]);
leftPart = leftPart.replace(currencies, "<span class='currency'>$1</span>");
rightPart = fCols[j] + parts.pop();
tds[j].innerHTML = "<span class='left'>" + leftPart + "</span><span class='right'>" + rightPart + "</span>";
} else {
tds[j].innerHTML = tds[j].innerHTML.replace(currencies, "<span class='currency'>$1</span>");
tds[j].innerHTML = "<span class='left'>" + tds[j].innerHTML + "</span>";
}
tds[j].className = "char-align";
var txt = document.createTextNode(tds[j].firstChild.offsetWidth);
if(leftWidth < tds[j].firstChild.offsetWidth) {
leftWidth = tds[j].firstChild.offsetWidth;
}
if(tds[j].childNodes[1]) {
txt = document.createTextNode(tds[j].childNodes[1].offsetWidth);
if(rightWidth < tds[j].childNodes[1].offsetWidth) {
rightWidth = tds[j].childNodes[1].offsetWidth;
}
}
}
}
}
}
}
// This is ugly and should be improved (amongst other parts of the code ;)
var styleText = "\n" +
"<style type='text/css'>\n" +
" .fix-align-char td.char-align { width: " + (leftWidth + rightWidth) + "px; }\n" +
" .fix-align-char span.left { float: left; text-align: right; width: " + leftWidth + "px; }\n" +
" .fix-align-char span.currency { text-align: left; float: left; }\n" +
" .fix-align-char span.right { float: right; text-align: left; width: " + rightWidth + "px; }\n" +
"</style>\n";
document.body.innerHTML += styleText;
})();
table {
border-collapse: collapse;
width: 600px;
}
th {
padding: .5em;
background: #eee;
text-align: left;
}
td {
padding: .5em;
}
#only-css td.char-align {
width: 7em;
}
#only-css span.left {
float: left;
width: 4em;
text-align: right;
}
#only-css span.currency {
float: left;
width: 2em;
text-align: left;
}
#only-css span.right {
float: right;
width: 3em;
text-align: left;
}
<table id="only-css">
<thead>
<tr>
<th>Number</th>
<th>Description</th>
<th>Costs</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Lorem ipsum dolor sit amet</td>
<td class="char-align">
<span class="left">
<span class="currency">$</span>3
</span>
<span class="right">,99</span>
</td>
</tr>
<tr>
<td>2</td>
<td>Consectetuer adipiscing elit</td>
<td class="char-align">
<span class="left">
<span class="currency">$</span>13
</span>
<span class="right">,95</span>
</td>
</tr>
<tr>
<td>3</td>
<td>Pellentesque fringilla nisl ac mi</td>
<td class="char-align">
<span class="left">
<span class="currency">$</span>4
</span>
<span class="right"></span>
</td>
</tr>
<tr>
<td>4</td>
<td>Aenean egestas gravida magna</td>
<td class="char-align">
<span class="left">
<span class="currency">$</span>123
</span>
<span class="right">,999</span>
</td>
</tr>
</tbody>
</table>
Another way to format a number would be like this: 35<span style="visibility: hidden">.000</span>. That is, write it out with the full decimal expansion, but write the trailing decimals in invisible ink. That way you don't have to worry about the width of the decimal point.
I'm surprised that in 10 years of answers to this question, nobody ever mentioned the Unicode character 'FIGURE SPACE' (U+2007, )
It's a whitespace character that is designed (by font authors, if they follow the standard) to be the same width as digits and to keep its spacing, like its more famous cousin the No-Break Space. You can use it to pad numbers to a certain string size, either on the left or on the right hand side, taking care of aligning the column or div on the same side.
Examples, both left-aligned and left-padded with figure spaces:
<p style="font-family: sans-serif">
10000 <br>
123.4 <br>
3.141592
</p>
<p style="font-family: serif">
10000 <br>
123.4 <br>
3.141592
</p>
Cheat; benefit of this solution: also works for proportional fonts. Have one extra column and split the integer part from the decimal separator and the decimals. Then use this css and combine two columns in the header row:
table {border-collapse:collapse;}
td {padding:0px;margin:0px;border:0px;}
td+td {text-align:right;}
td, td+td+td {text-align:left;}
<table>
<tr><th>Name</th><th colspan=2>Height</th></tr>
<tr><td>eiffeltower</td> <td>324</td> <td></td></tr>
<tr><td>giraffe</td> <td>5</td> <td>,30</td></tr>
<tr><td>deer</td> <td>1</td> <td></td></tr>
<tr><td>mouse</td> <td>0</td> <td>,03</td></tr>
</table>
Caveat: It isn't guaranteed to work. For example, on Safari 14 in 2021:
I played around with jQuery & came up with this...
$(document).ready(function() {
$('.aBDP').each(function() {
var wholePart, fractionPart;
wholePart = Math.floor($(this).text()-0);
fractionPart = Math.floor(($(this).text() % 1)*10000 + 0.5) / 10000 + "";
html = '<span class="left">' + wholePart + '.' + '</span>';
html += '<span class="right">' + fractionPart.substring(2) + '</span>';
$(this).html(html);
})
})
.right {
text-align: left;
}
.left {
float:left;
text-align: right;
width:10em;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js" type="text/javascript"></script>
<table width="600" border="1">
<tr><th></th><th>Aligned Column</th></tr>
<tr><th>1st Row</th><td class='aBDP'>1.1</td></tr>
<tr><th>2nd Row</th><td class='aBDP'>10.01</td></tr>
<tr><th>3rd Row</th><td class='aBDP'>100.001</td></tr>
<tr><th>4th Row</th><td class='aBDP'>1000.0001</td></tr>
</table>
It seemed to work.
can you just print the numbers so that they always have the same number of decimal places, and right align them?
Thousands of years ago (or 2-3) I wrote a jQuery shim that emulates align="char" which still seems to work. It uses CSS padding and accounts for colspans, so it's moderately clever, but it's really not very pretty code (I was just starting out in javascript back then). I'd love for someone to rewrite it (and take all the credit).
In the mean time, see if this helps you: https://gist.github.com/mattattui/f27ffd25c174e9d8a0907455395d147d
Trivia: The reason that browsers don't properly support column styles is that tables are 2D data structures and the DOM (which is what Javascript and CSS operate on, and how HTML5 is defined) is purely hierarchical and therefore can't represent both columns and rows. Instead it simply defines rows and cells, and doesn't represent columns at all.
I love short answers, even though the long ones are important too, so I liked;
35<span style="color:transparent">.000</span>
and would just like to add;
<TD><div style='float:right;'><?php echo number_format($totalAmount,2); ?></div></TD>
just to throw php into the mix. Much depends on fixed width fonts, still, but the latter works for me. Since data oft is already tabular, adding another table within a cell is just too much typing and hard to maintain.
If the numbers are monospaced, javascript could be used to adjust the padding on the cell (in ems), depending on the number of digits before the decimal point. Otherwise, it could be tricky.
The function made by Krijn Hoetmer interferes with prettyPhoto ( http://www.no-margin-for-errors.com/projects/prettyphoto-jquery-lightbox-clone/ ) so I made a jQuery version. The currency part is removed as it should be made dynamic instead of replacing strings based on predefined currencies.
Needed is the empty function from phpjs: http://phpjs.org/functions/empty:392 .
The jQuery used, is version 1.6.
/* This function will align table columns on the char if in the col from the
* colgroup has the property 'align="char"' and a attribute 'char'. The alignment
* is done on the first occurence of the specified char.
*
* The function is inspired from:
*
* http://krijnhoetmer.nl/stuff/javascript/table-align-char/
* http://stackoverflow.com/questions/1363239/aligning-decimal-points-in-html
*/
function alignNumbers()
{
var table; /* This will store the table currently working on . */
var i = 0; /* Every column can have it's own width, the counter makes the class name unique. */
/* Get all tables for which the alignment fix must be done.
*
* Note: this could even be further optimized by just looking for tables where
* there is a a col with 'align="char"'.
*/
$('table.fix-align-char').each(function(index)
{
table = $(this);
/* All table columns are fetched to have a correct index, without it it's
* hard to get the correct table cells.
*/
$(this).find('col').each(function(index)
{
/* Only those table cells are changed for which the alignment is set to
* char and a char is given.
*/
if ($(this).prop('align') == 'char' && !empty($(this).attr('char')))
{
/* Variables for storing the width for the left and right part (in pixels). */
var left_width = 0, right_width = 0;
var col, left_part, right_part, parts, new_html;
i++; /* Increase the counter since we are working on a new column. */
col = $(this);
/* For the col index + 1 (nth-child starts counting at 1), find the table
* cells in the current table.
*/
table.find('> tbody > tr > td:nth-child('+ (index + 1) +')').each(function(index)
{
/* Split the html on the specified char. */
parts = $(this).html().split(col.attr('char'));
new_html = '';
/* The first element is always the left part. The remaining part(s) are
* the right part. Should there be more chars in the string, the right
* parts are rejoined again with the specified char.
*/
left_part = parts.shift();
right_part = parts.join(',');
/* Add a left part to the new html if the left part isn't empty*/
if (!empty(left_part))
{
new_html = new_html + '<span class="left">' + left_part + '</span>';
}
/* Add the specified char and the right part to the new html if
* the right part isn't empty*/
if (!empty(right_part))
{
new_html = new_html + col.attr('char') + '<span class="right">' + right_part + '</span>';
}
/* If there is a new html, the width must be determined and a class is
* added.
*
* Note: outerWidth is used instead of width so padding, margin and
* borders are taken into account.
*/
if (!empty(new_html))
{
$(this).html(new_html); /* Set the new html. */
$(this).addClass('char-align-' + i); /* Add a class to the table cell. */
/* Get the left span to determine its outer width. */
leftSpan = $(this).children('.left');
if (!empty(leftSpan) && left_width < leftSpan.outerWidth())
{
left_width = leftSpan.outerWidth();
}
/* Get the right span to determine its outer width. */
rightSpan = $(this).children('.right');
if (!empty(rightSpan) && right_width < rightSpan.outerWidth())
{
right_width = rightSpan.outerWidth();
}
}
});
/* Only if any width is larger then 0, add a style. */
if (left_width > 0 || right_width > 0)
{
style_text = '<style type="text/css">.fix-align-char td.char-align-' + (i) + ' span.left { float: left; text-align: right; width: ' + (left_width) + 'px; }\n.fix-align-char td.char-align-' + (i) + ' span.right { float: right; text-align: left; width: ' + right_width + 'px; }</style>';
$('head').append(style_text);
}
}
});
});
}
$(document).ready(function(){
alignNumbers();
});
I have used JavaScript to fix this issue...
This is my HTML.
<body>
<table id="nadis">
</tr>
</table>
</body>
This is my JavaScript.
var numarray = ["1.1", "12.20", "151.12", 1000.23,12451];
var highetlen = 0;
for(var i=0; i<numarray.length; i++){
var n = numarray[i].toString();
var res= n.split(".");
n = res[0];
if(highetlen < n.length){
highetlen = n.length;
}
}
for(var j=0; j<numarray.length; j++){
var s = numarray[j].toString();
var res= s.split(".");
s = res[0];
if(highetlen > s.length){
var finallevel = highetlen - s.length;
var finalhigh = "";
for(k=0;k<finallevel;k++){
finalhigh = finalhigh+ ' ';
}
numarray[j] = finalhigh + numarray[j];
}
var nadiss = document.getElementById("nadis");
nadiss.innerHTML += "<tr><td>" + numarray[j] + "</td></tr>";
}
A serious trouble in the previous approaches, is that only think in visual, but do not in other needs or uses of tables as sorting or filtering, where pure data is important.
Unfortunately CSS4 are not available yet. Then a valid solution could be pass the value and units or type unit in data attributes on td cell.
<!-- HTML-->
<table>
<tbody>
<tr>
<td data-value="1876.67542" data-unit="USD"></td>
</tr>
</tbody>
</table>
If a cell have a data value, it must read with javascript and updated to the decimal numbers that we requires.
// Javascript
let $td_value = document.querySelectorAll( 'td[data-item]' );
Array.from( $td_value ).forEach( $r => {
$r.textContent = parseFloat( $r.getAttribute('data-value') ).toFixed(2);
});
At the end, when we have normalized data, they will looks great with mono fonts and with their units placed using css selectors as before or after.
/* CSS */
td[data-value]{
font-family: monospace;
text-align: right;
}
td[data-unit]::after{
content: attr(data-unit]);
font-size: 85%;
padding-left: .2em;
opacity: .6;
}
I put an extended example in: https://jsfiddle.net/jam65st/wbo63xpu/12/
Ugly workaround but will save you from writing a lot of code:
You can find the max number in the array (list) of prices, then you can take the number of its digits and set inline style "width": (maxNumberDigits * 10)px - this is the ugly part!
And the container of this data (cell if its table) should have additionally
display:flex;
justify-content: flex-end;
Result:
I want to have a text area which shows how much i wrote in it and displays it on the bottom right of the textarea(inside the textbox ) out of the max length of the value.
cant find how to do so.
Thanks.
You can achieve this using jQuery with the following simple code:
var theCounter = $('#textareaLength'),
textarea = $('#myTextarea'),
maxLength = textarea.attr('length');
theCounter.text('0 / '+maxLength);
theCounter.css({
'top': (textarea.offset().top + textarea.height()) - theCounter.height(),
'left': (textarea.offset().left + textarea.width()) - theCounter.width()
});
textarea.on('keydown', function() {
var theLength = $(this).val().length;
theCounter.text($(this).val().length+' / '+maxLength)
.css({
'left': (textarea.offset().left + textarea.width()) - theCounter.width()
});
});
Obviously you'll need to put in some logic to prevent any further action from occuring if the max length is met, but that should be pretty self-explanatory.
I've put together a jsFiddle for you.
Here is a function you can use
JAVASCRIPT:
function CountWords(s) {
var maxChars = 2048;
if (s.value.length > maxChars) {
s.value = s.value.substring(0, maxChars);
}
else {
$($(s).parent()).find("#words").html((maxChars - s.value.length) + " characters left.");
}
}
HTML:
<textarea onkeyup="CountWords(this)" id="txtBody" rows="50" cols="10"
></textarea>
<span id="words" style="width: 120px; color:Gray; display: block; float: left; margin: 5px; line-height: 27px;">
2048 characters left.</span>
you can just change the numbers to how many letter limit you want.
I have a question in regards to a progress bar. I've read pretty much all the posts here but it appears I can't make any of them work in my scenario.
I have the following which shows numbers such as 50/500 where 50 is the actual number and 500 is the max.
$SQL = "SELECT * FROM db_ships WHERE ship_id = $user[ship_id] LIMIT 1";
$result = mysql_query($SQL);
while ($db_field = mysql_fetch_assoc($result)) {
print $db_field['shields'] . " / ";
print $db_field['max_shields'] . "";
Most progress bars that I see depict timeframes, I need to visually show the fraction
print $db_field['shields'] . " / ";
print $db_field['max_shields'] . "";
How can I place this so I can have a progress bar depicting the progress?
I am sorry I am not good at css. Any help would be greatly appreciated.
One simple way of doing it is placing a div inside a larger div and setting the percentage width of the inner div. Here's a fiddle showing what I mean.
You can get the percentage of max_shields by writing (Assuming they are both numbers)
$percentage = $db_field['shields'] * ($db_field['max_shields'] / 100);
Apply the percentage as the width of the inner div.
<div id="progress-inner" style="width: <?php echo $percentage; ?>%;"></div>
It would be a breeze to animate that progress bar using jQuery animate if you wanted to.
echo "<div class=\"progressbar_container\"><div class=\"progressbar\" style=\"width: ".($db_field['shields']/$db_field['max_shields']*100)."%\"></div></div>";
And define styles as needed. Maybe a border for the container and a background colour for the main bar. That's all there is to a basic progress bar.
<style type="text/css">
.table, th
{
background-color:Blue;
border-collapse:collapse;
}
<table class="table" >
<tr id = "row1" >
<td id ="cell1" class="td"></td>
</tr>
</table>
<script language="javascript" type="text/javascript" >
var i = 1;
var timerID = 0;
timerID = setTimeout("progress()",200);
var scell = '';
var sbase = '';
sbase = document.getElementById("cell1").innerHTML;
function progress()
{
var tend = "</tr></table>";
var tstrt = "<table><tr>";
scell = scell + "<td style='width:15;height:25' bgcolor=blue>";
document.getElementById("cell1").innerHTML = sbase + tstrt + scell + tend;
if( i < 50)
{
i = i + 1;
timerID = setTimeout("progress()",200);
}
else
{
if(timerID)
{
document.getElementById("cell1")
.innerHTML=document.getElementById("cell1").innerHTML
+ "</tr></table>";
clearTimeout(timerID);
}
}
}
</script>