-1

I have the following raw text that I wrap in a <pre> tag to salvage as much of the layout as possible:

<pre>

test

field 1 :   Foo
longer field 2  :   Bar
very long field 3   :   FooBar

other text and values

</pre>

The field and values are separated by a tab char (\t) a colon and a tab char(\t).

I would like to align the colons so the rendered result would be:

test

field 1             :       Foo
longer field 2      :       Bar
very long field 3   :       FooBar

other text and values

You'll find a jsfiddle here with my effort so far.

I don't have much control over the text but I tried to replace the \t:\t with a <span> so I get some control with css styling but so far not much joy.

This is the javascript I use to replace the \t:\t with a span:

$('pre').html(
        $('pre')
        .html()
        .split('\t:\t')
        .join('<span class="tab">&nbsp;:&nbsp;</span>'));

and added this css rule to float the <span> but that

.tab {
    background-color:red;
    width: 10em;
    display: inline-block;
    text-align: right;
    float: left;
}

renders the span at the start of each new line. I've tried also position: absolute to no avail.

What are my options to get the colons aligned?

rene
  • 41,474
  • 78
  • 114
  • 152

2 Answers2

11

Using CSS as the primary driver:

$(document).ready(function() {
    $('pre').html(
        $('pre')
        .html()
        .replace(/(.*)\t:\t(.*)/g,function(_,key,value) {
            return '<div class="row">'+
                '<span class="col">'+key+'</span>'+
                '<span class="col"> : </span>'+
                '<span class="col">'+value+'</span>'+
            '</div>';
        })
    );
});
pre {display:table}
.row {display:table-row}
.col {display:table-cell}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<pre>
    
    test
    
    field 1 : Foo
    longer field 2 : Bar
    very long field 3  : FooBar
    
    other text and values
    
    </pre>

The important thing here is that the JavaScript will scan for lines of the required format (key[tab]:[tab]value) and dress them up in suitable elements. The CSS then makes them uniform.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
9

Okay, so this was actually a pretty fun one to suss out.

Example fiddle with dynamic width

Here's what we're doing:

JavaScript

$(document).ready(function() {
    var arr = $('pre').html().split('\n');
    for (var i=0,l=arr.length;i<l;i++){
        if (arr[i].indexOf(':') > -1) {
            var pieces = arr[i].split(':');
            arr[i] = "<span class='left'>" + pieces[0] + "</span>: " + pieces[1];
        }
    }
    
    $('pre').html(arr.join("\n"));
    var maxWidth = Math.max.apply(null, $('.left').map(function () {
        return $(this).outerWidth(true);
    }).get());
    $('.left').css('width', maxWidth + 15);
});

CSS

.left {
    display: inline-block;
}

 


Explanation of JavaScript

We're separating your pre based on the line instead of the colon, here:

var arr = $('pre').html().split('\n');

Then we're iterating over that looking for a : to separate:

if (arr[i].indexOf(':') > -1)

If we find one, we know that we need to do our super-fancy custom alignment. We do that by splitting on the : and then wrapping the left side in a span, like so:

var pieces = arr[i].split(':');
arr[i] = "<span class='left'>" + pieces[0] + "</span>: " + pieces[1];

Then, we add the modified HTML back to the pre and run this fancy little calculation to find the widest piece:

var maxWidth = Math.max.apply(null, $('.left').map(function () {
  return $(this).outerWidth(true);
}).get());

Stolen shamelessly from this answer

Then apply the widest width to each left element plus an additional 15px of padding at the end.

$('.left').css('width', maxWidth + 15);

Hope that helps!

Community
  • 1
  • 1
Josh Burgess
  • 9,327
  • 33
  • 46