Finding Line-Wraps

Finding line-wraps

Here's what I ended up using (feel free to critique and copy for your own nefarious purposes).

First off, when the edit comes in from the user, it's broken up with $(editableElement).lineText(userInput).

jQuery.fn.lineText = function (userInput) {
var a = userInput.replace(/\n/g, " \n<br/> ").split(" ");
$.each(a, function(i, val) {
if(!val.match(/\n/) && val!="") a[i] = '<span class="word-measure">' + val + '</span>';
});
$(this).html(a.join(" "));
};

The newline replacement happens because the editing textbox is populated with $(editableElement).text(), which ignores <br/> tags, but they will still change the height of the following line in the display for typesetting purposes. This was not part of the initial objective, just fairly low-hanging fruit.

When I need to pull out formatted text, I call $(editableElement).getLines(), where

jQuery.fn.getLines = function (){
var count = $(this).children(".word-measure").length;
var lineAcc = [$(this).children(".word-measure:eq(0)").text()];
var textAcc = [];
for(var i=1; i<count; i++){
var prevY = $(this).children(".word-measure:eq("+(i-1)+")").offset().top;
if($(this).children(".word-measure:eq("+i+")").offset().top==prevY){
lineAcc.push($(this).children(".word-measure:eq("+i+")").text());
} else {
textAcc.push({text: lineAcc.join(" "), top: prevY});
lineAcc = [$(this).children(".word-measure:eq("+i+")").text()];
}
}
textAcc.push({text: lineAcc.join(" "), top: $(this).children(".word-measure:last").offset().top});
return textAcc;
};

The end result is a list of hashes, each one containing the content and vertical offset of a single line of text.

[{"text":"Some dummy set to","top":363},
{"text":"demonstrate...","top":382},
{"text":"The output of this","top":420},
{"text":"wrap-detector.","top":439}]

If I just want unformatted text, $(editableElement).text() still returns

"Some dummy set to demonstrate... The output of this wrap-detector."

Textarea - get each line, find line breaks

So the way I did it was:

  • Clone the textarea in question - $("#text") into a transparent textarea. Use transparent font.
  • Change id value of clone to, say, $("#newtext") and append it to DOM.
  • On every keyup, we take the value of $("#text") before this character's keyup. Put that value into $("#newtext") and check if $("#newtext").get(0).scrollHeight() > $("#newtext").height(). If true => this character caused a line break.
  • Increase rows of $("#newtext") in a loop until
    $("#newtext").get(0).scrollHeight() === $("#newtext").height()
  • Take text before this character, add a \n, add this character to $("#newtext").val()
  • Apply $("#newtext").val() to $("#text").val().
  • Remove $("#newtext") from DOM.
  • Repeat all of above steps on every keyup event

Above answer works on similar lines as - stackoverflow.com/questions/3738490/finding-line-wraps – evolutionxbox yesterday

So, basically we convert line breaks into newlines which can be found by using $("#text").val().split("\n").


(Note - If we don't append transparent textarea to the DOM, its scrollHeight() will be undefined)

Detect browser wrapped lines via javascript

I have to admit at first I thought this would be a daunting task since there is no way to task browser to tell you where auto wrap line breaks take place.

I've created a solution that first wraps each word in a span, then goes through all the spans to determine their top position in container. It then builds an array of indexes of line start and end spans and wraps each line of word spans in a wrapping span.

DEMO: http://jsfiddle.net/KVepp/2/

Possible Limitations:

  • Space added at end of each span may perhaps cause a span to break to
    a new line where text may not.
  • Not sure if each word span needs to be removed once lines are wrapped. ( very simple mod)
  • Assumes no other html in container other than text
  • Needs a little additional work to be turned into a plugin if needed
    for multiple containers
  • regex for words is simple split at space. Likely need additional
    regex for recurring spaces

HTML:

<div id="content">Lorem Ipsum<div> 

CSS:

#content{ position:relative}

JS:

var $cont = $('#content')

var text_arr = $cont.text().split(' ');

for (i = 0; i < text_arr.length; i++) {
text_arr[i] = '<span>' + text_arr[i] + ' </span>';
}

$cont.html(text_arr.join(''));

$wordSpans = $cont.find('span');

var lineArray = [],
lineIndex = 0,
lineStart = true,
lineEnd = false

$wordSpans.each(function(idx) {
var pos = $(this).position();
var top = pos.top;

if (lineStart) {
lineArray[lineIndex] = [idx];
lineStart = false;

} else {
var $next = $(this).next();

if ($next.length) {
if ($next.position().top > top) {
lineArray[lineIndex].push(idx);
lineIndex++;
lineStart = true
}
} else {
lineArray[lineIndex].push(idx);
}
}

});

for (i = 0; i < lineArray.length; i++) {
var start = lineArray[i][0],
end = lineArray[i][1] + 1;

/* no end value pushed to array if only one word last line*/
if (!end) {
$wordSpans.eq(start).wrap('<span class="line_wrap">')
} else {
$wordSpans.slice(start, end).wrapAll('<span class="line_wrap">');
}

}​

finding line-breaks in textarea that is word-wrapping ARABIC text

Well, instead of finding the line breaks (which is virtually impossible) you can force them into the textarea, using this function:

function ApplyLineBreaks(strTextAreaId) {
var oTextarea = document.getElementById(strTextAreaId);
if (oTextarea.wrap) {
oTextarea.setAttribute("wrap", "off");
}
else {
oTextarea.setAttribute("wrap", "off");
var newArea = oTextarea.cloneNode(true);
newArea.value = oTextarea.value;
oTextarea.parentNode.replaceChild(newArea, oTextarea);
oTextarea = newArea;
}

var strRawValue = oTextarea.value;
oTextarea.value = "";
var nEmptyWidth = oTextarea.scrollWidth;
var nLastWrappingIndex = -1;
for (var i = 0; i < strRawValue.length; i++) {
var curChar = strRawValue.charAt(i);
if (curChar == ' ' || curChar == '-' || curChar == '+')
nLastWrappingIndex = i;
oTextarea.value += curChar;
if (oTextarea.scrollWidth > nEmptyWidth) {
var buffer = "";
if (nLastWrappingIndex >= 0) {
for (var j = nLastWrappingIndex + 1; j < i; j++)
buffer += strRawValue.charAt(j);
nLastWrappingIndex = -1;
}
buffer += curChar;
oTextarea.value = oTextarea.value.substr(0, oTextarea.value.length - buffer.length);
oTextarea.value += "\n" + buffer;
}
}
oTextarea.setAttribute("wrap", "");
}

This function get ID of textarea and whenever there is word wrap, it push new line break into the textarea. Run the function in the form submit and you will get the text with proper line breaks in the server side code.

Tested successfully for IE, Chrome and Firefox feel free to see for yourself here: http://jsfiddle.net/yahavbr/pH79a/1/ (The preview will show the new lines)



Related Topics



Leave a reply



Submit