JavaScript - Visible Text of a DIV - javascript

----------------------------------------------------
| This is my text inside a div and I want the overf|low of the text to be cut
----------------------------------------------------
Please note that I want the overflow to be removed, so the CSS ellipsis property would not work for me. So basically, I want that the text above to appear like this:
----------------------------------------------------
| This is my text inside a div and I want the overf|
----------------------------------------------------
How is this possible with pure JavaScript?
EDIT
I need a JavaScript function to crop the text because I need to count the characters of the visible text.

Okay, I didn't see the addendum to the question. Although I had previously said it wasn't possible to do this using JavaScript and a font that isn't fixed-width... it actually is possible!
You can wrap each individual character in a <span>, and find the first <span> that is outside the bounds of the parent. Something like:
function countVisibleCharacters(element) {
var text = element.firstChild.nodeValue;
var r = 0;
element.removeChild(element.firstChild);
for(var i = 0; i < text.length; i++) {
var newNode = document.createElement('span');
newNode.appendChild(document.createTextNode(text.charAt(i)));
element.appendChild(newNode);
if(newNode.offsetLeft < element.offsetWidth) {
r++;
}
}
return r;
}
Here's a demo.

You can do this with Javascript. Here is a function that counts the number of visible characters in an element, regardless of external css sheets and inline styles applied to the element. I've only tested it in Chrome, but I think it is cross browser friendly:
function count_visible(el){
var padding, em, numc;
var text = el.firstChild.data;
var max = el.clientWidth;
var tmp = document.createElement('span');
var node = document.createTextNode();
tmp.appendChild(node);
document.body.appendChild(tmp);
if(getComputedStyle)
tmp.style.cssText = getComputedStyle(el, null).cssText;
else if(el.currentStyle)
tmp.style.cssText = el.currentStyle.cssText;
tmp.style.position = 'absolute';
tmp.style.overflow = 'visible';
tmp.style.width = 'auto';
// Estimate number of characters that can fit.
padding = tmp.style.padding;
tmp.style.padding = '0';
tmp.innerHTML = 'M';
el.parentNode.appendChild(tmp);
em = tmp.clientWidth;
tmp.style.padding = padding;
numc = Math.floor(max/em);
var width = tmp.clientWidth;
// Only one of the following loops will iterate more than one time
// Depending on if we overestimated or underestimated.
// Add characters until we reach overflow width
while(width < max && numc <= text.length){
node.nodeValue = text.substring(0, ++numc);
width = tmp.clientWidth;
}
// Remove characters until we no longer have overflow
while(width > max && numc){
node.nodeValue = text.substring(0, --numc);
width = tmp.clientWidth;
}
// Remove temporary div
document.body.removeChild(tmp);
return numc;
}
JSFiddle Example

You're trying to force a CSS problem into JavaScript. Put the hammer away and get out a screwdriver. http://en.wiktionary.org/wiki/if_all_you_have_is_a_hammer,_everything_looks_like_a_nail
Solving the answer of character count is probably irrelevant if you take a step back. The last character could be only partially visible, and character count is drastically different given font size changes, the difference of width between W an i, etc. Probably the div's width is more important than the character count in the true problem.
If you're still stuck on figuring out the characters visible, put a span inside the div around the text, use the css provided in other answers to this question, and then in JavaScript trim one character at a time off the string until the span's width is less than the div's width. And then watch as your browser freezes for a few seconds every time you do that to a big paragraph.

try this, it requires a fixed width if that is ok with you: http://jsfiddle.net/timrpeterson/qvZKw/20/
HTML:
<div class="col">This is my text inside a div and I want the overf|low of the text to be cut</div>
CSS:
.col {
width:120px;
overflow: hidden;
white-space:nowrap;
}​

.col { width:40px; overflow: hidden; white-space:nowrap; }
White-space: nowrap; is needed when the content has spaces.
Either way, long words in single lines do not appear. http://jsfiddle.net/h6Bhb/

Related

How to get column number based on text

I've divided the Html content (which belongs to an eBook) into multiple columns using the following steps.
1) I've added the HTML inside the content which is inside a container.
<body>
<div id="container">
<div id="content">
BOOK HTML CONTENT
<span id="endMarker"></span>
</div>
</div>
</body>
2) Next, I've added the CSS style of the content and the container as shown below:
#container {
width: 240px;
overflow: hidden;
background-color: yellow;
}
#content {
position: relative;
height: 30em;
-moz-column-width: 240px;
-webkit-column-width: 240px;
column-width: 240px;
-moz-column-gap: 10px;
-webkit-column-gap: 10px;
column-gap: 10px;
}
Now, I want to find the column number of the text (or a line) using javascript?
There are other questions on SO that show how to get the column number based on the id. In my case, there are no id's. The only thing available is the text (or line) and I need to get the column number by searching through the Html content.
Currently, I've two "solutions" to get the column number but they are incomplete.
1) I can find whether the text exists or not by using window.find(text) after that I'm not sure what I've to do.
2) Another option is to add <span> with an id to every line temporarily and remove it. Once added, I can get the total column count up to that line (like shown below).
columnCount = Math.floor($('#marker').position().left/(columnWidth + columnGap));
This will give a wrong number if the line is extended to another column.
The second solution is tricky and book content is huge. I don't think this is the best way to get the column number. I'm looking for a simpler solution.
Try this, made a workable version for your question.
jsfiddle link
Although OP didn't tag question with jQuery, but actually used jQuery inside the question, I use it too for cleaner code. (and fit the question)
What I do in this example:
Make a long content cross several pages to visualize paging (with css: column-width).
Click on previous / next to browse pages.
Input and click 'find' button, make found texts highlighted.
List all columns (pages) found with input text.
Click on the link and jump to column with searched text.
In detail I made temporary DOM elements to calculate column, and remove them right after to keep DOM tree clean.
2017/6/1 Edited: Added highlight color for searched text.
$('#find').click( () => {
var text = $('#findtext').val();
var columns = [];
var doms = [];
while (window.find(text, false)) {
var sel = window.getSelection();
if (sel) {
var range = sel.getRangeAt(0);
var el = document.createElement("span");
var frag = document.createDocumentFragment();
frag.appendChild(el);
range.insertNode(frag);
columns.push(Math.floor(el.offsetLeft/(_columnWidth + _columnGap)));
doms.push(el);
}
}
/// distinct
columns = columns.filter( (value, index, self) => self.indexOf(value) === index );
/// show result
$("#foundlist").empty();
for (var i=0; i<columns.length; i++)
$("#foundlist").append(`<li>Found in Column ${columns[i]+1}</li>`);
/// remove dom. keep dom tree clean
while (doms.length > 0) {
var dom = doms.pop();
dom.parentNode.removeChild(dom);
}
});
Instead of adding a <span> beforehand, you could temporarily insert it at the point where you find your text and remove it again as soon as you have identified the position.
The key is how to find text in a long document. The interface for this task is the TreeWalker, that can iterate through every text node in a DOM subtree.
How to insert an element in the middle of a text node was copied from here.
Your question did not state it, but used jQuery as a dependency. This solution is using only the vanilla DOM interfaces.
var columnWidth = 240,
columnGap = 10;
function getColumn(text) {
// the subtree to search in
var root = document.getElementById('content');
// define an iterator that only searches in text nodes
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
// filter the text nodes to those containing the search text
acceptNode: function(node) {
if ( node.data.includes(text) ) {
return NodeFilter.FILTER_ACCEPT;
}
}
});
// look if there is a result
if (treeWalker.nextNode()) {
var node = treeWalker.currentNode;
// get start index of found text
var index = node.data.indexOf(text);
// and split into two nodes, referencing the second part
var foundTextNode = node.splitText(index);
// define an empty inline element
var span = document.createElement('span');
// insert it between the two text nodes
var elem = node.parentElement;
elem.insertBefore(span, foundTextNode);
// compute the column from the position of the element
// you might have to account for margins here
var x = span.getBoundingClientRect().left - root.getBoundingClientRect().left;
var column = Math.floor(x / (columnWidth + columnGap));
// restore previous state
elem.removeChild(span);
elem.normalize();
return column;
} else {
// no result
return false;
}
}
The obvious limitation to this solution is that it will not find text that is spanning multiple nodes. So, if you have a text fragment
<p>The quick brown fox <em>jumps</em> over the lazy dog.</p>
a search for 'fox jumps over' will not find this sentence.

How to calculate width of text using javascript?

How to get the width of the text.
var e=document.createElement('span');
e.style.fontSize = scope.fontsize;
e.innerHTML = "test";
console.log(e.offsetWidth);
Width always comes as 0
It seems like you have to append the created element to the document.
var e=document.createElement('span');
document.body.appendChild(e);
e.style.fontSize = 14;
e.innerHTML = "test";
console.log(e.offsetWidth);
e.remove();
Output: 23
Hiding the element does not work ether.
e.style.display= "none";
Output: 0
To "hide it" you could add a CSS like that. But with the added remove() it will likely not show up anyway. But adding position:absolute; is a good idea, since this will prevent flickering of the rest of the html content.
position:absolute;
margin-left:-1000em;

Issues with text formatting after jQuery

I have used code form here: Overflowed text with html in another div - to get text to flow over in a new div. However, now I have formatting issues with the text.
The first word of every paragraph is somehow followed by a line-break.
You can see an example here: http://jsfiddle.net/hm2yfw61/9/
var currentCol = $('.box:first');
var text = currentCol.html();
currentCol.html('');
text = text.replace(/ (?![^<>]*>)/gi, '%^%');
var wordArray = text.split('%^%');
$.fn.hasOverflow = function () {
var div = document.getElementById($(this).attr('id'));
return div.scrollHeight > div.clientHeight;
};
for (var x = 0; x < wordArray.length; x++) {
var word = wordArray[x];
currentCol.append(word + ' ');
if (currentCol.hasOverflow()) {
currentCol = currentCol.next('.box');
}
}
Does anyone know how I can fix this?
Thanks.
-----UPDATE: I've updated the jsfiddle with the working solutions suggested in reference for others who may face similar problems ------
This might be a bit hacky, but try the following:
Add the following CSS rule
.box > p:first {
display: none;
}
Add "nbsp; " (including the space) at the beginning of each string in .box > p tags.
<p> Jumo handango
Updated Fiddle

Can I select an nth css column?

I have a div with 4 css columns and I'd like to select the 3rd and 4th column to make the text slightly darker because I don't have a good contrast between the text and the background-image. Is this possible? I can accept any css or js solution.
Here's the demo.
--EDIT--
It seems that it's not possible to find a selector for pseudo blocks (if I may say) however I still need to figure out a way of creating responsive blocks (like columns) that will split the text equally (in width) whenever the browser is resized.
As far as I know you won't be able to apply styles to the columns.
What you can try however is to use a gradient as a background to make columns 3 and 4 another color.
#columns {
background: -webkit-linear-gradient(left, rgba(0,0,0,0) 50%, blue 50%);
/*... appropriate css for other browser engines*/
}
updated jsFiddle
updated with all browser support gradient
-- EDIT --
Since the intention was actually to change the text color and not the background for the third and fourth column some additional thoughts.
For now it doesn't seem possible to apply styles to single columns inside a container. One possible workaround to change the text color in specific columns is to put every word inside a span. Then to use JavaScript to iterate over the words and determine where a new column starts. Assigning the first element in the third column a new class would make it possible to style this and the following siblings with a different text color.
Because the container is part of a responsive layout and could change in size, the script would have to be re-run on the resize event to account for changing column widths.
The purpose of the code example is to outline how to implement such a solution and should be improved for use in an actual application (e.g. the spans are being re-created every time styleCols is run, lots of console output...).
JavaScript
function styleCols() {
// get #columns
var columns = document.getElementById('columns');
// split the text into words
var words = columns.innerText.split(' ');
// remove the text from #columns
columns.innerText = '';
// readd the text to #columns with one span per word
var spans = []
for (var i=0;i<words.length;i++) {
var span = document.createElement('span');
span.innerText = words[i] + ' ';
spans.push(span);
columns.appendChild(span);
}
// offset of the previous word
var prev = null;
// offset of the column
var colStart = null;
// number of the column
var colCount = 0;
// first element with a specific offset
var firsts = [];
// loop through the spans
for (var i=0;i<spans.length;i++) {
var first = false;
var oL = spans[i].offsetLeft;
console.info(spans[i].innerText, oL);
// test if this is the first span with this offset
if (firsts[oL] === undefined) {
console.info('-- first');
// add span to firsts
firsts[oL] = spans[i];
first = true;
}
// if the offset is smaller or equal to the previous offset this
// is a new line
// if the offset is also greater than the column offset we are in
// (the second row of) a new column
if ((prev === null || oL <= prev) && (colStart === null || oL > colStart)) {
console.info('-- col++', colCount + 1);
// update the column offset
colStart = oL;
// raise the column count
colCount++;
}
// if we have reached the third column
if (colCount == 3) {
// add our new class to the first span with the column offset
// (this is the first span in the current column
firsts[oL].classList.add('first-in-col3');
return;
}
// update prev to reflect the current offset
prev = oL;
}
}
styleCols();
addEventListener('resize', styleCols, false);
CSS
.first-in-col3, .first-in-col3~span {
color: red;
}
jsFiddle
For now i dont think you can do it, here https://bugzilla.mozilla.org/show_bug.cgi?id=371323 is an open bug/request for a feature, you can vote for it. Till then you can consider using tables.
P.S.
Give Up and Use Tables just for the sake of humor :)
The only solution i could think would be a background with your desired color for middle column, customize it for size and position so it goes behind your middle columns and make background-clip:text. Unfortunately it is not supported very well.
You can find more explenations here.

Javascript Gets the contents of the textarea of the distance from the border pixels

How can I be sure the text in the input box, the number of pixels from the left box? It may have utf8, Chinese
This might not be the best way, but i guess this can be a start. This will return the number of pixels remaining in the input element:
function getRemainingWidth(element){
var span = $('<span class=\"'+$(element).attr('class')+'\" style=\"visibility:hidden;\">'+$(element).val()+'</span>');
$(document.body).append(span);
var diff = $(element).width() - $(span).width();
$(span).remove();
return diff;
}
One way to do it is creating a span element and adding your text to it. But there is a catch: you have to add it to the dom in order get its with:
var sYourText = 'asdfafdsa, dzcvxvxc';
var oText = document.createElement('span');
oText.innerHTML = sYourText;
document.getElementsByTagName('body')[0].appendChild(oText)
console.log(oText.offsetWidth);
Of course: be sure to apply the same font that your textarea have.
$("textarea").keyup(function(){
var s = $(this).val()
var data = s.replace(/(\s)/g,' ')
console.log(data)
$('span').html(data)
})
I replace it with a regular spaces replaced, but wrapping problems that may require using CSS

Categories

Resources