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
, addthis
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
Which "Href" Value Should I Use For JavaScript Links, "#" or "JavaScript:Void(0)"
Adding Two Numbers Concatenates Them Instead of Calculating the Sum
How to Get Value of Selected Radio Button
How to Make JavaScript Execute After Page Load
Html Text Input Allow Only Numeric Input
How to Modify Style to HTML Elements (Styled Externally With Css) Using Js
Set Cookie and Get Cookie With JavaScript
Stop Form Refreshing Page on Submit
Convert Data Uri to File Then Append to Formdata
How to Apply !Important Using .Css()
"Submit Is Not a Function" Error in JavaScript
Changing Website Favicon Dynamically
Calling a JavaScript Function in Another Js File
Calling Webpacked Code from Outside (Html Script Tag)
Edit, Save, Self-Modifying HTML Document; Format Generated Html, JavaScript