Javascript: Detecting if text would wrap - javascript

How can I detect if a piece of text would wrap?
So imagine I have a UI with a header that has largish text. I want the biggest text here that fits vertically in a menu bar. It displays numerical data like this:
LABEL: 9999 LABEL2: 99999
The number parts can get larger. On some screens - e.g. phones - it causes the element to overflow and wrap below the bar that it is supposed to stay in. I don't want to do overflow:hidden. I want the user to see the whole thing.
I'd like to be able to somehow calculate how big the element would be, and if it would wrap pre-emptively shrink the font, possibly move the element left to make space.

You can detect the difference between the different width properties of the containing element's width and scroll width if you set the white-space css handling to nowrap.
Here is a jsFiddle to demonstrate, and the code:
$(document).ready(function(){
$("#messages").append($("#aa").width() + " " + $("#aa").outerWidth() + " " + $("#aa")[0].scrollWidth);
});
#aa {
white-space: nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<div id="aa">lksjdlakj dla ldakjl skajd lkasjlkdas dlaskdjl aksjd laksdj laks djlkas dlkasjd lkasjdl alkdj laksdj alsklkajlksjad lkajsld kasjldkasjd lkjlsk djlkasdj llaskjdl aksdjlaksjd lkasjdlak sdl</div>
<div id="messages"></div>
Once you know that the scroll width is wider than the width, you can then resize the text or do what you need to do until it isn't.

Nice #WooCaSh. Here is an application in CoffeeScript:
autoGrow = ->
(scope, element, attrs) ->
update = ->
if element[0].scrollWidth > element.outerWidth isBreaking = true else isBreaking = false
element.css 'height', 'auto' if isBreaking
height = element[0].scrollHeight
element.css 'height', height + 'px' if height > 0
scope.$watch attrs.ngModel, update
attrs.$set 'ngTrim', 'false'
# Register
App.Directives.directive 'autoGrow', autoGrow

Related

jQuery UI Layout - How change a pane's options and dynamically apply them without toggling the pane open/closed?

http://jsfiddle.net/jc3rj681/2/
Using the plugin jQuery UI Layout, I have several different panes. When the user resizes the window to a small size, I would like to call a function that changes the minsize and size of the pane so that I can make it smaller with the window.
I can do this, but for the changes to apply, I must toggle closed and then toggle open the pane. This creates a lot of flickering and ends up being pretty messy looking. I only need this one pane to resize in this fashion.
QUESTION: Is there a way I can apply these layout changes without having to toggle the pane twice for them to apply?
Check out this Fiddle that I made: http://jsfiddle.net/jc3rj681/2/
In here, the changes to the "width" of the show/hide button don't get applied until you toggle the pane. If you can make this width change work without toggling, I'm sure it would solve my problem as well.
$("#eastToggle").click(function () {
testLayout.toggle('east');
});
$("#attempt").click(function () {
testLayout.options.east.spacing_closed = 20;
testLayout.options.east.spacing_open = 20;
});
I'm not sure if there is a callback function or any special utility method that'll do the trick.
But you can try something like the following (probably with a resize function that'll resize the panes manually) -
var testLayout = $('body').layout({
applyDefaultStyles: true,
east: {
spacing_closed: 100, //toggler width
spacing_open: 100,
togglerLength_closed: 200, //toggler height (length)
togglerLength_open: 200
}
});
$("#eastToggle").click(function() {
testLayout.toggle('east');
});
$("#attempt").click(function() {
resize('east', 20);
});
// A function to resize the tab
function resize(region, space) {
// Width of the new center pane
var newCenterWidth = parseInt($('body .ui-layout-center').css('width').split('px')[0]) + testLayout.options.east.spacing_closed - space;
// Change the options so they don't affect the layout when you expand / collapse again
testLayout.options.east.spacing_closed = space;
testLayout.options.east.spacing_open = space;
// Manually resize the panes
$('body .ui-layout-resizer-' + region).css('width', space);
$('body .ui-layout-center').css('width', newCenterWidth);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://layout.jquery-dev.net/lib/js/jquery.layout-latest.js"></script>
<div class="ui-layout-center">Center</div>
<div class="ui-layout-north">North</div>
<div class="ui-layout-south">South</div>
<div class="ui-layout-east">East</div>
<div class="ui-layout-west">West
<br/>
<br/>
<button id="eastToggle">Toggle East Panel</button>
<br/>
<br/>
<button id="attempt">Change Width?</button>
</div>

Dynamically position text within a td element of a table.

I am trying to position text within a viewport so that as the user scrolls along the viewport the text in the column remains visible for as long as possible. The issue is that the view port may be smaller than the width of the column in the table. So I have something close to working here: http://jsfiddle.net/Deterus/6eU24/15/
$rowDiv.scroll(function (e) {
$headerDiv.css({
left: -$rowDiv[0].scrollLeft + 'px'
});
var thresh = $('.peek').width();
$.leftofscreen("#lookInMe", ".peek", {
threshold: thresh
}).removeClass("textAdjustTL").addClass("textAdjustTR");
$.rightofscreen("#lookInMe", ".peek", {
threshold: thresh
}).removeClass("textAdjustTR").addClass("textAdjustTL");
$.inviewportCenter("#lookInMe", ".peek", {
threshold: 0
}, thresh);
});
This is where I am able to add or manipulate the css needed to keep the row elements at the edge of the viewport. Currently the classes just align the text to the right or left and doesnt allow the sliding nature I need. Any leads would be appreciated.

Determining the Width and Height of an element: True and normal

I would like to know what the best method is to calculate the width and height of an element with Jquery/Javascript (or any other method that might be more accurate). Currently, I am using this Jquery method:
Jquery: See my example: http://jsfiddle.net/AwkF5/1/
var w = $("#wrapper"); //The element dimensions to calculate
$("#displayW").text( "outerWidth:" + w.outerWidth()+ " , outerWidth(true):" + w.outerWidth(true) ); // Displaying the width in the #displayW div
$("#displayH").text( "outerHeight:" + w.outerHeight()+ " , outerHeight(true):" + w.outerHeight(true) ); // Displaying the height in the #displayH div
Now is this the most accurate way to calculate the width/height(including content, padding and border) and TRUE width/height ((including content, padding, border and margin) of an element?
What would be the plain javascript method?
I'm asking because I want to make a background image for the div and I want to know what size it should be...Note that the width and height varies between different browsers...obviously
Thank You
​
This should work for you:
var realWidth = $("#yourBlockId").outerWidth();
realWidth += parseInt($("#yourBlockId").css("margin-left"), 10);
realWidth += parseInt($("#yourBlockId").css("margin-right"), 10);
The same approach for height.

CSS: Child div overlapping parent

I have something vaguely like the following:
<div id="body">
surrounding text
<div id="pane" style="overflow: auto; height: 500px; width: 500px;">
lots and lots of text here
<span id="some_bit">tooltip appears below-right of here</span>
</div>
more surrounding text (should be overlapped by tooltip)
</div>
and:
<div id="tooltip" style="width: 100px; height: 100px;">Whee</div>
What I want to do is insert the tooltip such that it is positioned above the pane it's in. If it's attached to an element that's next to the pane boundary (like above), then it should be visible above the pane, and above the text surrounding the pane.
It should NOT a) extend the pane, such that you have to scroll down to see the tooltip (like in http://saizai.com/css_overlap.png), or b) be cut off, so you can't see all of the tooltip.
I'm inserting this with JS, so I can add a wrapper position:relative div or the like if needed, calculate offsets and make it position:absolute, etc. I would prefer to not assume anything about the pane's position property - the tooltip should be insertable with minimal assumptions of possible page layout. (This is just one example case.)
It's for a prototype tooltip library I'm writing that will be open source.
ETA: http://jsfiddle.net/vCb2y/5/ behaves visually like I want (if you keep re-hovering the trigger text), but would require me to update the position of the tooltip on all DOM changes and scrolling behavior. I would rather the tooltip be positioned with pure CSS/HTML so that it has the same visual behavior (i.e. it overlaps all other elements) but stays in its position relative to the target under DOM changes, scrolling, etc.
ETA 2: http://tjkdesign.com/articles/z-index/teach_yourself_how_elements_stack.asp (keep defaults except set cyan div 'a' to position:relative; imagine 'A' is the pane and 'a' the tooltip) seems to more closely behave as I want, but I've not been able to get it to work elsewhere. Note that if you make 'A' overflow: auto, it breaks the overlapping behavior of 'a'.
I can't think of a pure HTML/CSS solution for this.
The overflow declaration is the issue here. If the tooltip is in #pane:
you establish a positioning context within #pane, then the tooltip shows next to #some_bit (regardless of scrolling, etc.) but it gets cut-off.
you do not establish a positioning context, then the tooltip is not clipped but it has no clue where #some_bit is on the page.
I'm afraid you'll need JS to monitor where #some_bit is on the page and position the tooltip accordingly. You'd also need to kill that tooltip as soon as #some_bit is outside of the viewing area (not an issue if the trigger is mouseover).
Actually, if the trigger is mouseover then you may want to use the cursor coordinates to position the tooltip (versus calculating the position of #some_bit).
I would just put the tooltip outside of the #pane div and position it absolutely using JavaScript since you're using JS anyway.
I don't use Prototype so I don't know how it's done in Prototype, but in jQuery, you'd use $(element).position() to get the element position. If you have to do it manually, it's a little more complicated.
And you'll probably want to add a little extra logic to prevent the tooltip from extending outside of the document.
Edit: CSS used
#tooltip {
z-index: 9999;
display: none;
position: absolute;
}
JS used
Note: in jQuery, but it should be easy to change it to Prototype syntax.
$('#some_bit').hover(function() {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
// hovered element
var offset = $(this).offset();
var top = offset.top + docViewTop;
var left = offset.left;
var width = $(this).width();
var height = $(this).height();
var right = left + width;
var bottom = top + height;
// pane
var poffset = $('#pane').offset();
var ptop = poffset.top + docViewTop;
var pleft = poffset.left;
var pwidth = $('#pane').width();
var pheight = $('#pane').height();
var pright = pleft + pwidth;
var pbottom = ptop + pheight;
// tooltip
var ttop = bottom;
var tleft = right;
var twidth = $('#tooltip').width();
var theight = $('#tooltip').height();
var tright = tleft + twidth;
var tbottom = ttop + theight;
if (tright > pright)
tleft = pright - twidth;
if (tbottom > pbottom)
ttop = pbottom - theight;
if (tbottom > docViewBottom)
ttop = docViewBottom - theight;
$('#tooltip').offset({top: ttop, left: tleft});
$('#tooltip').css('display', 'block');
}, function() {
$('#tooltip').hide();
});
Edit: See it here.

DIV Vertical Scroll bar on left

Is it possible to put DIV's Vertical Scroll bar on left of the div with css? what about jscript?
I had a simple use case so opted for a simple css solution:
<div style="direction: rtl; height: 250px; overflow: scroll;">
<div style="direction: ltr; padding: 3px;">
Content goes here
</div>
</div>
You can add a pseudo-scrollbar anywhere you want with JQuery and this plug-in: JScrollPane
Okay, so, I wrote a jQuery plugin to give you a completely-native-looking left scroll bar.
Left Scrollbar Hack Demo
Here's how it works:
Inject an inner div inside the pane to allow calculation of the content width (content_width). Then, using this, the native scrollbar width can be calculated: scrollbar_width = parent_width - content_width - horizontal_padding .
Make two different divs inside the pane, both filled with the content.
One's purpose is being a "poser". It's used solely for the scrollbar. Using a negative left margin, the plugin pulls it left so that only the scrollbar is in view (the content of this div is clipped off at the edge).
The other div is used to actually house the visible scrolling content.
Now, it's time to bind the two together. Every 50ms (window.setInterval), the scrollTop offset from the "poser" div is applied to the visible, scrolling content div. So, when you scroll up or down with the scrollbar on the left, the scroll offset gets applied back on the div with the visible content.
This explanation probably sucks and there's actually a quite a bit more to it that I didn't describe, but, without further ado, here it is:
$.fn.leftScrollbar = function(){
var items = $(this);
$(function(){
items.each(function(){
var e = $(this);
var content = e.html();
var ie = !jQuery.support.boxModel;
var w = e[ie?'innerWidth':'width'](), h = e[ie?'innerHeight':'height']();
//calculate paddings
var pad = {};
$(['top', 'right', 'bottom', 'left']).each(function(i, side){
pad[side] = parseInt(e.css('padding-' + side).replace('px',''));
});
//detect scrollbar width
var xfill = $('<div>').css({margin:0, padding:0, height:'1px'});
e.append(xfill);
var contentWidth = xfill.width();
var scrollerWidth = e.innerWidth() - contentWidth - pad.left - pad.right;
e.html('').css({overflow:'hidden'});
e.css('padding', '0');
var poserHeight = h - pad.top - pad.bottom;
var poser = $('<div>')
.html('<div style="visibility:hidden">'+content+'</div>')
.css({
marginLeft: -w+scrollerWidth-(ie?0:pad.left*2),
overflow: 'auto'
})
.height(poserHeight+(ie?pad.top+pad.bottom:0))
.width(w);
var pane = $('<div>').html(content).css({
width: w-scrollerWidth-(ie?0:pad.right+pad.left),
height: h-(ie?0:pad.bottom+pad.top),
overflow: 'hidden',
marginTop: -poserHeight-pad.top*2,
marginLeft: scrollerWidth
});
$(['top', 'right', 'bottom', 'left']).each(function(i, side){
poser.css('padding-'+side, pad[side]);
pane.css('padding-'+side, pad[side]);
});
e.append(poser).append(pane);
var hRatio = (pane.innerHeight()+pad.bottom) / poser.innerHeight();
window.setInterval(function(){
pane.scrollTop(poser.scrollTop()*hRatio);
}, 50);
});
});
};
Once you've included jQuery and this plugin in the page, apply the left scroll bar:
$('#scrollme').leftScrollbar();
Replace #scrollme with the CSS selector to the element(s) you wish to apply left scrollbars to.
(and, obviously, this degrades nicely)

Categories