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-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."
How to find whether text in a text area is wrapped to multiple lines?
I experimented on this and came up with a hack that involves the following:
Disabling text-wrapping in the textarea (plus disable padding)
Checking if the textarea's
scrollWidth
is greater than it'swidth
.
The basic logic i used was that if the text is spanning multiple lines, that means when wrapping is turned off, we should get a horizontal scrollbar.
Demo: http://jsfiddle.net/fnG3d/
Disclaimer: The code below is the result of a 10 minute fiddle, definitely not production quality
function checkMulti(id) {
var ta = $('#'+id), multi = false;
// disable wrapping, padding and enable horiz scoll
ta.addClass('nowrap');
// check if there is anything to be scrolled horizontally (means multi-lines otherwise)
multi = ( ta[0].scrollWidth > ta.width() );
// checking done. remove the class.
ta.removeClass('nowrap');
alert('Spread over multiple-lines: ' + multi);
}
/* the nowrap class */
.nowrap {
overflow-x: scroll;
white-space: nowrap;
padding: 0;
}
JS: Detecting wrapped inline elements?
You can check the offsetHeight
property of the elements and watch for it to jump. When an inline element has a greater offsetHeight
than the previous element, this element is on a new line.
How to track lines count when words are wrapped?
How about using overflow: hidden?
Say you had a font-size
of 12px, and a line-height
of 16px.
4 lines * 16px = 64px
.hide-extra-lines {
height: 64px;
overflow: hidden;
}
Is this what you're after?
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
)
Detecting line-breaks in browser/css-forced line breaks
Well, assume that your text is in a <p id='wholeText'>
:
var element = document.getElementById("wholeText");
var wholeText = element.innerHTML;
var splitText = wholeText.split("\r\n");
var newHtml = null;
for(var i = 0; i < splitText.length; i++)
{
newHtml += "<p class='each-line'>"+splitText[i]+'</p>';
}
Then you can use newHtml
to write in a DOM element. For instance, if you like to add it to a the same <p>
which you got text from, you do:
element.innerHTML = newHtml; // remember element refers to the <p> with the ID of wholeText
Also put all of the above codes into a function and call the function after the windows has been fully loaded.
window.addEventListener("load", function(){
// put the code here
}, false);
If your line does not contain break characters
, then please refer to this plugin :
http://jsfiddle.net/nathan/qkmse/
The above link is suggested in this SO's question:
detecting line-breaks with jQuery?
Related Topics
Set Default Value for a Input File Form
JavaScript on the Bottom of the Page
Increment a Number in a String in with Regex
Counting and Limiting Words in a Textarea
How to Build Simple Tabs with Jquery
Getelementsbyclassname() with Two Classes
JavaScript Code Not Work in Head Tag
Onclick Calling Hide-Div Function Not Working
Using Canvas to Animate a Sorting Algorithm in Js
Jquery Validation Using the Class Instead of the Name Value
How to Remove Youtube Branding After Embedding Video in Web Page
Store Jquery Selector in Variable
How to Tell Google Translate to Not Translate a Section of a Website
How to Disable Div Element and Everything Inside