I am trying to grab the HTML from a CSS truncated element and can't seem to get it right.
For example:
<span id=mySpan style=white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:50px>This is the contents of the span tag. It should truncate with an ellipsis if it is longer than 50px.</span>
If I use the standard jQuery way to grab the HTML, I get the full text, not the truncated version. I'm not sure if it is even possible.
html = jQuery('#mySpan').html();
text = jQuery('#mySpan').text();
Both return the full text. I'm stumped.
You can compute it :
$.fn.renderedText = function(){
var o = s = this.text();
while (s.length && (this[0].scrollWidth>this.innerWidth())){
s = s.slice(0,-1);
this.text(s+"…");
}
this.text(o);
return s;
}
var renderedText = $("#mySpan").renderedText(); // this is your visible string
Demonstration
Of course this only works for an element with overflow:hidden;text-overflow:ellipsis but it's easy to adapt when there's no text-overflow:ellipsis: just remove the +"…".
Note that this is compatible with all browsers and gives the exact result (the w3.org specifies that the … character is to be used by the browser).
#dystroy has given a nice answer, here is another (more future-friendly) way to do this though.
We can use document.caretPositionFromPoint. This is almost a FF only function, but most other browsers provide the same thing under their own function name and API. No I don't know what browsers have against devs but oh well...
Our method works like this:
select element
get bounding client position
put it in the above function to get text offset position
subtract 3 from it to remove the ellipsis thingy from the offset
extract text according to that offset from textContent property
Here is a quick demo (should work properly in Webkit and Gecko):
function getRenderedText (el) {
var pos = el.getBoundingClientRect();
var offset, range;
if (document.caretRangeFromPoint) {
range = document.caretRangeFromPoint(pos.right, pos.top);
offset = range.endOffset - 3;
}
else if (document.caretPositionFromPoint) {
range = document.caretPositionFromPoint(pos.right, pos.top);
offset = range.offset - 3;
}
else {
console.error('Your browser is not supported yet :(');
}
return el.textContent.slice(0, offset);
}
console.log(getRenderedText(el));
span {
text-overflow: ellipsis;
width: 40px;
white-space: nowrap;
display: block;
overflow: hidden;
}
<span id="el">foo bar is so much awesome it is almost the bestest thing in the world. devs love foo bar. foo bar all the things!</span>
I have seen an error of maximum 1 character in some cases (weird fonts or edge cases), but most of the time, it works fine.
Hope that helps!
Related
Is it possible to get the width (using javascript or jQuery) of a float-affected element? When text is being pushed over due to a floating image is it possible to get its position and true width? I have attached an image to explain better.
Code example,
<div>
<img style="...float: left"/>
<h1>A title!</h1>
<p>Text!</p>
<h1>New header added.</h1>
</div>
Picture
I need to find the width starting from the arrow, (the gray box is the image)(the dotted line is the width according to Firefox inspect mode).
I would like to avoid changing all the elements display types if possible.
Thank you!
I'm a little late to the party, but I had a similar problem and came up with a solution which (so far) seems to work in all instances of this issue. I like this solution because as far as I can tell, it works independent of the floating element - all you need is the element whose true width/position you want to get, nothing more. I've done it in pure Javascript for speed purposes, but it can easily be streamlined with jQuery and a separate CSS Stylesheet if you so choose.
//Get the rendered bounding box for the content of any HTMLElement "el"
var getLimits = function(el) {
//Set a universal style for both tester spans; use "!important" to make sure other styles don't mess things up!
var testerStyle = 'width: 0px!important; overflow: hidden!important; color: transparent!important;';
//Create a 'tester' span and place it BEFORE the content
var testerStart = document.createElement('SPAN');
testerStart.innerHTML = '|';
var testerFloat = ' float: left!important;';
testerStart.setAttribute('style', testerStyle + testerFloat);
//Insert testerStart before the first child of our element
if (el.firstChild) {
el.insertBefore(testerStart, el.firstChild);
} else {
el.appendChild(testerStart);
}
//Create a 'tester' span and place it AFTER the content
var testerEnd = document.createElement('SPAN');
testerEnd.innerHTML = '|';
testerFloat = ' float: right!important;';
testerEnd.setAttribute('style', testerStyle + testerFloat);
el.appendChild(testerEnd);
//Measure the testers
var limits = {
top: testerStart.offsetTop,
bottom: testerEnd.offsetTop + testerEnd.offsetHeight,
left: testerStart.offsetLeft,
right: testerEnd.offsetLeft
}
//Remove the testers and return
el.removeChild(testerStart);
el.removeChild(testerEnd);
return limits;
};
So, in your case, the code would just be:
var paragraphBoundingBox = getLimits($('div>p').get(0));
A couple things to note:
1) The float direction would be reversed if you are using an RTL language
2) All of the four edge positions in the output object are relative to the el.offsetParent - use this handy function can find their positions relative to the document.
First of all, the "full width" is exactly the true width.
You can watch this picture, it can help you understand why the true width and true position of the affected element is the way firefox tells you.
http://i.stack.imgur.com/mB5Ds.png
To get the width of inline text where it's pushed right by the float image, there's no good way except using the full width minus the float image's width.
var w = $('p').width()
- $('img').width()
- $('img').css('margin-left').replace("px", "")
- $('img').css('margin-right').replace("px", "")
- $('img').css('padding-left').replace("px", "")
- $('img').css('padding-right').replace("px", "")
- $('img').css('border-left-width').replace("px", "")
- $('img').css('border-right-width').replace("px", "");
Is there a way to check if the CSS function calc is available using JavaScript?
I found lot of questions and articles about getting the same behaviour as calc using jQuery, but how can I only check if it's available?
In Modernizr you can find the test as css-calc currently in the non-core detects. They use the following code:
Modernizr.addTest('csscalc', function() {
var prop = 'width:';
var value = 'calc(10px);';
var el = document.createElement('div');
el.style.cssText = prop + Modernizr._prefixes.join(value + prop);
return !!el.style.length;
});
A bit late to the party but I figured I should share this because I was myself struggling with it. Came up with the idea of by using jQuery, I can create a div that uses the calc() value in a CSS property (such as width in this case) and also a fallback width in case the browser does not support calc(). Now to check whether it supports it or not, this is what I did:
Let's create the CSS style for the currently "non-existing" div element.
/* CSS3 calc() fallback */
#css3-calc {
width: 10px;
width: calc(10px + 10px);
display: none;
}
Now, if the browser does not support calc(), the element would return a width value of 10. If it does support it, it would return with 20. Doesn't matter what the values are exactly, but as long as the two width properties have different values in the end (in this case 10 and 20).
Now for the actual script. It's pretty simple and I suppose it's possible with regular JavaScript too, but here's the jQuery script:
// CSS3 calc() fallback (for unsupported browsers)
$('body').append('<div id="css3-calc"></div>');
if( $('#css3-calc').width() == 10) {
// Put fallback code here!
}
$('#css3-calc').remove(); // Remove the test element
Alternatively, native javascript check, and width:
#css3-calc { width: 1px; width: calc(1px + 1px); }
if( document.getElementById('css3-calc').clientWidth==1 ){
// clientHeight if you need height
/* ... */
}
Calc detection was added to modernizer according to their news page.
http://modernizr.com/news/
As well as tightening up support for existing tests, we've also added
a number of new detects, many submitted by the community:
[...]
css-calc
var cssCheck = document.createElement("DIV");
cssCheck.style.marginLeft = "calc(1px)";
if (cssCheck.style.getPropertyValue("margin-left"))
{
alert("calc is supported");
}
cssCheck = null;
I want to trim a string down to a particular pixel width so that it can properly fit in a container. It will be similar to substring, except that I am trimming based on pixel width as opposed to number of characters. is there a built in function for this?
Maybe this is what you're looking for:
jQuery Text Overflow plugin
Lg
warappa
You can do it via css: text-overflow: clip;
Note: This is not supported in FF < 7. Every other browser including IE6 supports it.
Try this:
function trimByPixel(str, width) {
var spn = $('<span style="visibility:hidden"></span>').text(str).appendTo('body');
var txt = str;
while (spn.width() > width) { txt = txt.slice(0, -1); spn.text(txt + "..."); }
return txt;
}
CSS might be the easiest/best option, especially if you're trying to keep text confined to an area. Check out both word-wrap and text-overflow, as they might be v
I need a Jquery script to truncate a text paragraph by line (not by character count).
I would like to achieve an evenly truncated text-block. It should have a "more" and "less" link to expand and shorten the text paragraph. My text paragraph is wrapped in a div with a class, like this:
<div class="content">
<h2>Headline</h2>
<p>The paragraph Text here</p>
</div>
The closest solution i could find on SOF is the one below (but it`s for textarea element and does not work for me):
Limiting number of lines in textarea
Many thanks for any tips.
Ben
For a basic approach, you could take a look at the line-height CSS property and use that in your calculations. Bear in mind that this approach will not account for other inline elements that are larger than that height (e.g. images).
If you want something a bit more advanced, you can get the information about each line using getClientRects() function. This function returns a collection of TextRectangle objects with width, height and offset for each one.
See this answer here for an example (albeit an unrelated goal) of how getClientRects() works.
Update, had a bit of time to come back and update this answer with an actual example. It's basic, but you get the idea:
http://jsbin.com/ukaqu3/2
A couple of pointers:
The collection returned by getClientRects is static, it won't update automatically if the containing element's dimensions change. My example works around this by capturing the window's resize event.
For some strange standards-compliance reason that I'm not understanding, the element you call getClientRects on must be an inline element. In the example I have, I use a container div with the text in another div inside with display: inline.
I made this little jQuery code to allow me truncate text blocks by line (via CSS classes), feel free to use and comment it.
Here is the jsFiddle, which also include truncate functions by char count or word count. You can see that currently, resize the window won't refresh the block display, I'm working on it.
/*
* Truncate a text bloc after x lines
* <p class="t_truncate_l_2">Lorem ipsum magna eiusmod sit labore.</p>
*/
$("*").filter(function () {
return /t_truncate_l_/.test($(this).attr('class'));
}).each(function() {
var el = $(this);
var content = el.text();
var classList = el.attr('class').split(/\s+/);
$.each(classList, function(index, item){
if(/^t_truncate_l_/.test(item)) {
var n = item.substr(13);
var lineHeight = parseInt(el.css('line-height'));
if(lineHeight == 1 || el.css('line-height') == 'normal')
lineHeight = parseInt(el.css('font-size')) * 1.3;
var maxHeight = n * lineHeight;
var truncated = $.trim(content);
var old;
if(el.height() > maxHeight)
truncated += '...';
while(el.height() > maxHeight && old != truncated) {
old = truncated;
truncated = truncated.replace(/\s[^\s]*\.\.\.$/, '...');
el.text(truncated);
}
}
});
});
why not make the p element with overflow: hidden; give fixed line height, caluclate the height of the div so id contains exactly the number of lines you require and the only change the height of the p from javascript.
p{
overflow:hidden;
line-height:13px;
height:26px; /* show only 2 rows */
}
<script type="text/javascript">
function seeMoreRows(){
$(p).height("52px");
}
</script>
I made a small module that works with pure text content, no nested tags and no css-padding on the text-containing element is allowed (but this functionality could easily be added).
The HTML:
<p class="ellipsis" data-ellipsis-max-line-count="3">
Put some multiline text here
</p>
The Javascript/Jquery:
( function() {
$(document).ready(function(){
store_contents();
lazy_update(1000);
});
// Lazy update saves performance for other tasks...
var lazy_update = function(delay) {
window.lazy_update_timeout = setTimeout(function(){
update_ellipsis();
$(window).one('resize', function() {
lazy_update(delay);
});
}, delay);
}
var store_contents = function(){
$('.ellipsis').each(function(){
var p = $(this);
p.data('ellipsis-storage', p.html());
});
}
var update_ellipsis = function(){
$('.ellipsis').each(function(){
var p = $(this);
var max_line_count = p.data('ellipsis-max-line-count');
var line_height = p.html(' ').outerHeight();
var max_height = max_line_count*line_height;
p.html(p.data('ellipsis-storage'));
var p_height = p.outerHeight();
while(p_height > max_height){
var content_arr = p.html().split(' ');
content_arr.pop();
content_arr.pop();
content_arr.push('...');
p.html(content_arr.join(' '));
p_height = p.outerHeight();
}
});
}
} )();
I hope you like it!
If you used a monospaced font, you'd have a shot at this working, as you'd have a good idea how many letters fit onto each line, for an element of a defined width. However, if a word breaks across lines, then this might get tricky..
e: found another question which is basically what you're after - they didn't really have a resolution either, but to my mind, the line-height and element height seems closest.
"How can I count text lines inside a dom element"
tl;dr - set a height on your container div and then use the jQuery dotdotdot plugin
Was about to make #Andy E's awesome example into a plugin, but then realized https://github.com/BeSite/jQuery.dotdotdot could pull this off. Our use case is we want to show one line on desktop widths and two lines on mobile/tablet.
Our CSS will just set the container div to the equivalent of one or two line-height's accordingly and then the dotdotdot plugin appears to handle the rest.
I get this problem in IE7 when running a piece of code that uses jquery and 2 jquery plugins. The code works in FF3 and Chrome.
The full error is:
Line: 33
Char: 6
Error: bg is null or not an object
Code: 0
URL: http://localhost/index2.html
However line 33 is a blank line.
I am using 2 plugins: draggable and zoom. No matter what I do to the code it is always line 33 that is at fault. I check the source has update via view source but I feel this could be lying to me.
<body>
<div id="zoom" class="zoom"></div>
<div id="draggable" class="main_internal"><img src="tiles/mapSpain-smaller.jpg" alt=""></div>
<script type="text/javascript">
$(document).ready(function() {
$('#draggable').drag();
$('#zoom').zoom({target_div:"draggable", zoom_images:new Array('tiles/mapSpain-smaller.jpg', 'tiles/mapSpain.jpg') });
});
</script>
</body>
Essentially what I am trying to do is recreate the Pragmatic Ajax map demo with jQuery.
It would appear that the second line of this snippet is causing the trouble:
bg = $(this).css('background-position');
if(bg.indexOf('%')>1){
It seems to be trying to select the background-position property of #draggable and not finding it? Manually adding a background-position: 0 0; didn't fix it. Any ideas on how to get around this problem?
I tried using the MS Script Debugger but that is nearly useless. Can't inspect variables or anything else.
A bit more digging about on the Interweb has revealed the answer: IE doesn't understand the selector background-position. It understands the non-standard background-position-x and background-position-y.
Currently hacking something together to workaround it.
Nice one, Redmond.
To get around the fact that Internet Explorer does not support the "background-position" CSS attribute, as of jQuery 1.4.3+ you can use the .cssHooks object to normalize this attribute between browsers.
To save yourself some time, there is a background position jQuery plugin available that allows both "background-position" and "background-position-x/y" to work as expected in browsers that don't support one or the other by default.
It is interesting. IE8 doesn't understand getter backgroundPosition, but it understands setter.
$('.promo3').mousewheel(function(e,d){
var promo3 = $(this);
var p = promo3.css('backgroundPosition');
if (p === undefined) {
p = promo3.css('backgroundPositionX') + ' ' + promo3.css('backgroundPositionY');
}
var a = p.split(' ');
var y = parseInt(a[1]);
if (d > 0) {
if (y < -1107) y += 1107;
y -= 40;
}
else {
if (y > 1107) y -= 1107;
y += 40;
}
promo3.css('backgroundPosition', a[0] + ' ' + y + 'px');
return false;
});
It works great in IE8 and IE8 compatible view.
This worked for me:
if (navigator.appName=='Microsoft Internet Explorer')
{
bg = $(drag_div).css('backgroundPositionX') + " " + $(drag_div).css('backgroundPositionY');
}
else
{
bg = $(drag_div).css('background-position');
}
hope it does for you.
You may want to check to make sure that you are loading your js files in the correct order so that any dependencies are taken into account.
A bit of thinking (and a cup of tea) later I came up with:
if(bg == 'undefined' || bg == null){
bg = $(this).css('background-position-x') + " " + $(this).css('background-position-y');
}
Unfortunately it returns center center despite the online resources I can find state it should return 0 0 if the values are undefined.
Beginning to wonder if there is an actual fix/workaround to this. A lot of people have tried and all so far fail to catch all edge cases.
The camelCase version of backgroundPosition seems viable but I don't know enough of jQuery to make an accurate assessment of how to go about it - from what I have read you can only use camelCase as getters if the property has been set previously. Please tell me if I am mistaken.
However line 33 is a blank line.
It'll be line 33 of one of your .js files, not line 33 of the HTML itself. IE fails to report which actual file the error was in. Look at line 33 of each .js for something about ‘bg’; if the worst comes to the worst you can start inserting newlines at the start of each .js and see whether the line number changes.
I check the source has update via view source but I feel this could be lying to me.
View source will always show you what IE got from the server. It won't show any updates to the DOM.
try backgroundPosition istead
Also, make sure that 'this' exists and that your request for an attribute returns a value. IE will throw this kind of errors when you try to call a method on a property that does not exist, therefore bg is null or null an object. if you dont care about IE you can do bg = $(this)... || '' so that theres always something referenced.
Also, unrelated to the error you're getting, but is your index value of 1 correct? Did you mean -1 ?
Yupp, Try background-position instead or just set the background-position with jquery before you call it. Ill guess one often knows the positions through CSS before calling it. It isnt pretty, but somehow it did the trick for me.)
eg:
//set it in with javascript.
$("someid").css("background-position", "10px 0");
...
//do some funky stuff
//call it
$("someid").css("background-position");
//and it would return "10px 0" even in IE7
if nothing helps, it's also possible to make the following trick.
We can replace a background of an element by an inner absolutely positioned element (with the same background). The coordinates will be replaced by left and top properties. This will work in all browsers.
For better understanding, please, check the code:
Before
<div></div>
div {
background: url(mySprite.png);
background-position: -100px 0;
}
After
<div>
<span></span>
</div>
div {
position: relative;
overflow: hidden;
width: 100px; /* required width to show a part of your sprite */
height: 100px; /* required height ... */
}
div span {
position: absolute;
left: -100px; /* bg left position */
top: 0; /* bg top position */
display: block;
width: 500px; /* full sprite width */
height: 500px; /* full sprite height */
background: url(mySprite.png);
}
This solution is not very flexible, but it helped me to show icons hover state properly.
You can't use dashes in the jquery css function. You have to do it in camelCase:
.css('backgroundPosition') or .css('backgroundPositionX') and .css('backgroundPositionY') for IE