Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

to apply sequential line numbering to lines in a paragraph: is it possible?

Is it possible to have jquery/javascript insert sequential line number at the start of all lines in a paragraph and, better still, to follow the sequence through to subsequent paragraphs?

I want to be able to refer students quickly to particular lines of an article (in a classroom setting). I have lots of articles to which I would like to apply this functionality, each of which has varying numbers of paragraphs.

I was hoping this might be possible, even in a responsive page, where the width of the paragraphs changes, depending on the display device, and the consequent number of lines in each paragraph becomes greater or fewer.

Thanks in advance to anyone who can help.

like image 611
user2195707 Avatar asked Oct 15 '13 21:10

user2195707


2 Answers

Here is one approach that may suit your purposes.

  1. Get the height of a one-line paragraph, for reference.
  2. For each paragraph, get the actual height, and infer the number of lines.
  3. Loop through the lines and add the numbering at absolute positions.

var refHeight = $("p").eq(0).height();
$("p").eq(0).remove();
var cnt = 1;
$("p").each(function(index) {
    var pos = $(this).position();
    var h = $(this).height();
    var lines = h / refHeight;
    var lineHeight = h / lines;
    for (var i=pos.top ; i<pos.top+h ; i += lineHeight) {
        var num = $("<p>", { class: "number" });
        num.text(cnt++);
        num.css("top", i);
        $(this).before(num);
        console.log(i);
    }
});

(Fiddle)


Edit

If you wanted to use a fixed line length (so that everyone is seeing the same numbers), you could combine the above with the following:

  1. Break the paragraphs into lines.
  2. Wrap each line in a span/div, and re-append.
  3. Block the browser from text wrapping.

$("p").each(function() {
    var text = $(this).text();
    $(this).html("");
    var i=0;
    while (i<text.length) {
        lineCharWidth = charWidth;
        while (i+lineCharWidth < text.length && text[i+lineCharWidth] != ' ') {
            lineCharWidth++;
        }
        var line = $("<span>", { class: "line" }).text(text.substr(i, lineCharWidth));
        $(this).append(line).append("<br/>");
        i += lineCharWidth;
    }
});

(Fiddle)

like image 140
McGarnagle Avatar answered Sep 24 '22 02:09

McGarnagle


Here's a solution that uses a function to split the paragraph text on space characters based on a pre-determined line length and then replaces the text with an <ol> comprised of <li> elements each containing one line of text:

var lineNum = 1;

function splitLines(text, lineLen) {
    var words = text.split(/\s/g), line = '', lines = [];
    $.each(words, function(idx) {
        line += this + ' ';
        if (line.length > lineLen || idx == words.length - 1) {
            lines.push(line);
            line = '';
            lineNum += 1;
        }
    });
    return lines;
}

$('p').each(function() {
    var $p = $(this), $ol = $('<ol start="' + lineNum + '">'), lineLen = 50;

    $.each(splitLines($p.text(), lineLen), function(idx) {
        $ol.append('<li>' + this + '</li>');
    });

    $p.text('').append($ol);
});

I'm not sure about the support for the start attribute of the <ol>. It does work in Chrome. Even still, I like using the list element because it's a little more semantically meaningful, in my opinion.

like image 21
FishBasketGordo Avatar answered Sep 26 '22 02:09

FishBasketGordo