Calculate container height of pinboard style blog (based on absolute elements) - javascript

I'm developing a pinboard-style blog (like Pinterest) using the tutorial by Ben Holland. Each pin has an absolute position and its location (top and left) is being calculated with jQuery script http://labs.benholland.me/pinterest/js/script-centered.js
Everything works perfectly (see demo), but the only thing that needs doing is adding footer. When I try to add footer (no matter how it is positioned: relatively or absolutely), it shows up either on the top of the page (position:relative) or it floats somewhere in the middle of the page (position:absolute;bottom:0). Footer never shows up underneath the blog.
I tried many CSS solutions (clearfixes, floats, a variety of different position combinations), after all this I came to the conclusion that it is impossible without JS.
The problem can be solved by placing the pinboard in the container, giving the container position:relative and adding the correct height. After this, footer can be placed below the container. And this is where I'm stuck.
I'm a beginner at JavaScript, can somebody help me to to this?

Just as you said,you may use a div to contain these absolute elements
The construct like:
<body onload="setupBlocks();">
<header>header</header>
<section id="container">
<div class="block">
<p>Lorem ipsum dolor sit amet....</p>
</div>
......
</section>
<footer>footer</footer>
</body>
and css code like:
header{height:30px;background-color:green;}
footer{height:20px;background-color:gray;}
section{position:relative;} //It's important,absolute element will calculate position depending on nearest parent which has sure position.
as to js code,Please look at array:block[],this array has the record of every column's height,you can print it in console.
so what you need to do is just set max value of block[] to section.
here I added two lines in function positionBlocks and a function to get max value
function positionBlocks() {
$('.block').each(function(i){
var min = Array.min(blocks);
var index = $.inArray(min, blocks);
var leftPos = margin+(index*(colWidth+margin));
$(this).css({
'left':(leftPos+spaceLeft)+'px',
'top':min+'px'
});
blocks[index] = min+$(this).outerHeight()+margin;
});
var max = Array.max(blocks); //you need to write a function to get max value of block
$('section').height(max); //set section(or div,as you wish)'s height
}
// Function to get the Min value in Array
Array.min = function(array) {
return Math.min.apply(Math, array);
};
// Function to get the Max value in Array
Array.max = function(array) {
return Math.max.apply(Math, array);
};
if you want to let your foot in the end if section's height too small,you need to calculate (scollheight-other's height)、compare with section's height and replace it in set seciton's height line.

Related

pagination depending on window size - approach to find number of items per page

Sorry for being long and thank you very much for your usual time and guidance.
I have a div of unknown dimensions; in fact, its width and height are set using percentages so the final values in pixels depend on the window innerWidth an innerHeight properties.
I need to create an ajax pagination inside that div. In other words, I have two child div s (figure below). The second one is for pagination links. The first one is responsible of holding items (aligned horizontally and vertically). It will be (automatically) of unknown width . As a result, the number of items inside depend on its final width and height because all items have a fixed known width and hieght (Let's say 80 pixels width and 50 pixels height).
I hope the following figure is illustrating my issue in the best manner:
The goal is to find a good approach to find the values of X and Y.
X= number of items per row
Y= the number of items per column
These two values will help finding the number of items per page (to be used server side for pagination). Pagination links will be created by dividing the total number of pages by this value. Note: Everything is done with ajax.
What I am planning to do:
create a javascript function calculate_viewport() to be the first thing to execute before any other thing parsed/exectued.
create a javascript function that calculates X and Y values based on values returned by calculate_viewport().
use the X and Y for an ajax call that request a certain page.
<script type="text/javascript">
function calculate_viewport() {
var width_and_height_object;
// calcluate width and height using of current window.innerWidth and window.innerHeight
// put values in an object width_and_height_object
return width_and_height_object; }
function calculate_XandY(width_and_height_object) {
var XandY_object;
// calcluate X and Y values by perfoming necessary division operations
return XandY_object; }
var XandY = calculate_XandY(viewport()); </script>
<!DOCTYPE html> <html>
<head>
</head>
<body>
<div id="parent" style="height: 70%; width: 50%">
<div id="items_container" style="height: calc(100% - 30px); width: 100%"></div>
<div id="pagination" style="height: 30px; width: 100%">></div>
</div>
</body>
<script src="jquery.js"></script>
<script type="text/javascript">
$('a.next a.previous').click(function(e){
e.preventDefault();
$.ajax({
type: "GET",
url: url_to_page_of_items,
data: { number_of_items_per_page : X_times_Y },
cache: false,
success: callback // append result to items container div
});
return false;
});
</script> </html>
What do you think about this approach? Are there any other better ways to achieve this goal? Is it acceptable to create a <script> tag before the <html> tag just to make early window size calculation?
N.B: For the server side part, I manage to paginate results via some functions offered by the ORM library I am using. I use a server-side template engine that renders a page of items as HTML. I am ready to provide any code upon request for this part. Thanks
You'll never get the layout math right on your own. My recommendation is to lay out all of the items before hand (flex box is ideal here!), get the count, and then fill them in using ajax.
Here's a quick demo I whipped up. The actual JS is pretty simple, using jQuery.
var MARGIN = 10; //This should match your CSS
var itemContainerHeight = $(".foo").height();
var count = 0;
$(".item").each(function () {
if ($(this).position().top + $(this).height() + MARGIN > itemContainerHeight) {
$(this).hide();
} else {
count++;
}
});
$('.pagination').text("I can display "+count+" items!");
The important line is the one containing .position(). That'll get the location of each of the items top edge, add the height to find their bottom edge, and check if it's past the bounds of the item container.
After this you can just use the count to query the necessary items from the server. I'd also recommend using visbility: hidden; on all of the items so the user doesn't see them before they're ready.

How do I get the height of a textarea

I need to get the height of a textarea. Seemingly so simple but it's driving me mad.
I have been researching for ages on stackoverflow with no luck: textarea-value-height and jquery-js-get-the-scrollbar-height-of-an-textarea and javascript-how-to-get-the-height-of-text-inside-of-a-textarea, among many others.
This is how it looks currently:
This is how I want it to look, open a full height:
.
Here is my html:
<textarea id="history" class="input-xxlarge" placeholder="Enter the content ..." rows="13"></textarea>
CSS:
.input-xxlarge {
display: inline-block;
height: auto;
font-size: 12px;
width: 530px;
resize: none;
overflow: auto;
}
jQuery:
var textarea = $('#history');
I've tried (inter alia):
1. textarea.height() --> always returns 0
2. textarea.ready(function() { // wait for DOM to load
textarea.height();
}
3. getting scrollheight from textarea as an HTMLTextareaElement (i.e. DOM Element) --> returns 0
4. var contentSpan = textarea.wrapInner('<span>');
var height = contentSpan.height(); --> always returns 0
Please help, I'm at my wit's end!
Ok, I've found a solution. Whether it's the best solution, I don't know, but it works and that, frankly, is all I care about, having spent almost a day on this issue.
Here it is for anyone who faces the same problem:
Select the textarea:
var textarea = $('#history');
Get the textarea's text:
var text = textarea.text();
Create a temporary div:
var div = $('<div id="temp"></div>');
Set the temp div's width to be the same as the textarea. Very important else the text will be all on one line in the new temp div!:
div.css({
"width":"530px"
});
Insert the text into the new temp div:
div.text(text);
Append it to the DOM:
$('body').append(div);
Get the height of the div:
var divHeight = $('#temp').height();
Remove the temp div from the DOM:
div.remove();
Had a similar issue, in my case I wanted to have an expand button, that would toggle between two states (expanded/collapsed). After searching also for hours I finally came up with this solution:
Use the .prop to get the content height - works with dynamically filled textareas and then on a load command set it to your textarea.
Get the inner height:
var innerHeight = $('#MyTextarea').prop('scrollHeight');
Set it to your element
$('#MyTextarea').height(innerHeight);
Complete code with my expand button(I had min-height set on my textarea):
$(document).on("click", '.expand-textarea', function () {
$(this).toggleClass('Expanded');
if($(this).hasClass('Expanded'))
$($(this).data('target')).height(1);
else
$($(this).data('target')).height($($(this).data('target')).prop('scrollHeight'));
});
Modern answer: textarea sizing is a few lines of ES6 implementable two primary ways. It does not require (or benefit from) jQuery, nor does it require duplication of the content being sized.
As this is most often required to implement the functionality of auto-sizing, the code given below implements this feature. If your modal dialog containing the text area is not artificially constrained, but can adapt to the inner content size, this can be a perfect solution. E.g. don't specify the modal body's height and remove overflow-y directives. (Then no JS will be required to adjust the modal height at all.)
See the final section for additional details if you really, truly only actually need to fetch the height, not adapt the height of the textarea itself.
Line–Based
Pro: almost trivial. Pro: exploits existing user-agent behavior which does the heavy lifting (font metric calculations) for you. Con: impossible to animate. Con: extended to support constraints as per my codepen used to explore this problem, constraints are encoded into the HTML, not part of the CSS, as data attributes.
/* Lines must not wrap using this technique. */
textarea { overflow-x: auto; white-space: nowrap; resize: none }
for ( let elem of document.getElementsByTagName('textarea') ) {
// Prevent "jagged flashes" as lines are added.
elem.addEventListener('keydown', e => if ( e.which === 13 ) e.target.rows = e.target.rows + 1)
// React to the finalization of keyboard entry.
elem.addEventListener('keyup', e => e.target.rows = (elem.value.match(/\n/g) || "").length + 1)
}
Scrollable Region–Based
Pro: still almost trivial. Pro: animatable in CSS (i.e. using transition), though with some mild difficulty relating to collapsing back down. Pro: constraints defined in CSS through min-height and max-height. Con: unless carefully calculated, constraints may crop lines.
for ( let elem of document.getElementsByTagName('textarea') )
elem.addEventListener('keyup', e => {
e.target.style.height = 0 // SEE NOTE
e.target.style.height = e.target.scrollHeight + 'px'
})
A shocking percentage of the search results utilizing scrollHeight never consider the case of reducing size; for details, see below. Or they utilize events "in the wrong order" resulting in an apparent delay between entry and update, e.g. pressing enter… then any other key in order to update. Example.
Solution to Initial Question
The initial question specifically related to fetching the height of a textarea. The second approach to auto-sizing, there, demonstrates the solution to that specific question in relation to the actual content. scrollHeight contains the height of the element regardless of constraint, e.g. its inner content size.
Note: scrollHeight is technically the Math.max() of the element's outer height or the inner height, whichever is larger. Thus the initial assignment of zero height. Without this, the textarea would expand, but never collapse. Initial assignment of zero ensures you retrieve the actual inner content height. For sampling without alteration, remove the height override (assign '') or preserve (prior to) then restore after retrieval of scrolllHeight.
To calculate just the height of the element as-is, utilize getComputedStyle and parse the result:
parseInt(getComputedStyle(elem).height, 10)
But really, please consider just adjusting the CSS to permit the modal to expand naturally rather than involving JavaScript at all.
Place this BEFORE any HTML elements.
<script src="/path/to/jquery.js"></script>
<script>
$(document).ready(function(){
var textarea = $('#history');
alert(textarea.height()); //returns correct height
});
</script>
You obviously do not have to alert it. I was just using an easily visible example.
Given a textarea with an id of "history", this jQuery will return it's height:
$('#history').height()
Please see a working example at http://jsfiddle.net/jhfrench/JcGGR/
You can also retrieve the height in pixels by using $('#history').css('height'); if you're not planning on doing any calculations.
for current height in px:
height = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('height')
for current width in px:
width = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('width')
change 'textarea' to '#history' or like a css selector. or textarea, since a variable is declared to select element.

vertically center page around a form

I know vertical center in CSS is a pain to begin with, but I've just made it a bit more complicated. On my page, I have:
<ul id="complete">
</ul>
<form id="new_item_form">
<input type="text" id="add_item" placeholder="Type some tasks here"/>
</form>
<ul id="incomplete">
</ul>
It's for a basic task list. Tasks are added to the incomplete ul, and when completed move to the complete ul. What I want to do via css is have the text field vertically centered on the page and stay there, with the two lists butted up against it. I've been looking at all sorts of vertical alignment (a summary of forms found here: http://blog.themeforest.net/tutorials/vertical-centering-with-css/ ) but I can't seem to find a way that I can figure out how to adapt to allow what I need. How would I accomplish this style of fixed position centering?
EDIT:
Here's an image of what I'm looking for: https://www.dropbox.com/s/i0oit3v84j93b5g/Screen%20Shot%202012-10-11%20at%204.27.16%20PM.png
Is this what you want to obtain?
Of course, my code is a bit sketchy (use of height attribute on tds! Don't scold me to much). But you get the point.
If the height of the table is not known nor fix, but its parent height is known, it won't work (see this example) and you'll have to break it down.
If you just don't know any height at all, it's kind of hard to align...
Further reading on vertical-align
I can't think of any way to do this with CSS, but it's fairly easy to do with JavaScript/jQuery. Here is a working jsFiddle that does what you want on document load. You'd call the code again if you changed the lists, of course.
First, you enclose your lists and form in a div. I called this id="cmiddle". Then you use CSS to set the cmiddle div as position: relative. Then you use JavaScript code to get the enclosing window or frame height, calculate the center for the form, and then, subtract the upper list height to get the correct div position:
$(document).ready(function(e) {
// To work with frames, too
function getParentDocHeight($ele) {
for (;;) {
if (!$ele || !$ele.length) {
return $(window).height();
}
$ele = $ele.parent();
if ($ele.is("frame") || $ele.is("window")) {
return $ele.height();
}
}
}
var $cm = $("#cmiddle");
var formHeight = $("#new_item_form").outerHeight();
var viewHeight = getParentDocHeight($cm)
var formTop = (viewHeight - formHeight) / 2;
var divTop = formTop - $("#complete").outerHeight();
$cm.css("top", divTop);
});
Edit: Kraz was nice enough to add a simulation of adding list items to both lists and calling the code again to recalc. His jsFiddle here.
Well, I'm not sure what you are talking about
But generally,
put the line-height = the div's height. I will create a div around it if necessary
if some very particular situations, i do some math to manually center it
So if you want to centering 1 thing, create a div go around it with line-height = the div's height
And then make the div position: absolute, width, height, ....
Hope this helps

I can't get a Div's width using element.style.width. Do I have to use element.clientWidth instead?

I think I'm going mad!
I'm starting to write a little exercise for myself where I am going to have some divs that I can drag on the rightborder to increase or decrease the Div width. I also have a container Div that has a set width and I'm going to use this to determine a percentage - basically I'm going to be making some kind of bar-chart / histogram that you can edit.
I'm started writing my code and I thought I'd just make sure I could output the percentage.
Here's the perliminary code....
<style>
#container{width:500px;}
#dragDiv{border:1px solid #000;background-color:pink;width:100px;height:100px;}
</style>
</head>
<body>
<div id="container">
<div id="dragDiv"></div>
</div>
<script>
function dragOneSide(innDiv, outDiv){
if(document.getElementById(innDiv) && document.getElementById(outDiv)){
var iDiv = document.getElementById(innDiv),
oDiv = document.getElementById(outDiv);
// write out the width as a percentage
var iDivWidth = parseInt(iDiv.style.width),
oDivWidth = parseInt(oDiv.style.width);
//alert(document.getElementById("dragDiv").style.width);
iDiv.innerHTML = ((iDivWidth / oDivWidth) * 100);
}
}
window.onload = function(){
dragOneSide("dragDiv", "container");
}
</script>
Now the value in the iDiv was NaN? I found that rather odd. When trying to alert width I was getting a blank, literally an empty string! Rather odd I thought, especially as I wasn't trying to do anything complicated. I used firebug, set a breakpoint and observed the watch window. There was no value for the Div's width. I then put an inline style on the DIV like so...
<div id="container">
<div id="dragDiv" style="width:300px;">Hello World</div>
</div>
and low and behold I was now getting a value for the item! Now I don't like inline styles (who does) however I've never had this problem before and I've been using JavaScript and HTML for years - has anyone got an explaination for this? To retrieve the width not set by CSS do I have to use a different property like clientWidth?
Ps. I haven't included any of the dragging code yet so please don't point that out.
The call to style.width retrieves the style value, which isn't set.
http://jsfiddle.net/EC2HR/
See this example. Yes, you want to use clientWidth in this case.
The simplest way is to use offsetWidth property:
var iDivWidth = parseInt(iDiv.style.offsetWidth),
oDivWidth = parseInt(oDiv.style.offsetWidth);
style.width is a DOM api which returns the width of an element when it's set inline or via the element.style.width = n + "px";
So that it reacts the way you describe it is as designed.
The offsetWidth like ioseb refers to is a DOM api call which returns the amount of horizontal space an element takes up.
Beware of the many inconsistencies between browsers .
PM5544...

How to split html to full-screen height pages?

I need to split some html content to pages, so that each page would have height of the screen and some predefined width. Page split can happen in the middle of paragraph (or probably some other html element), so this situation should be handled somehow.
What I really want to achieve is the effect of reading the book, page by page. I assume there will be a need for some javascript, so I'd prefer to to this with jQuery, but if other framework is required, it's also okay.
I have to admit that I'm quite new to HTML and all, so sorry if my guess is stupid, but currently I'm considering the following approach: measure actual height of the visible area (need to figure out how yet), then take my html document and incrementally take tag after tag, put this into invisible div and calculate its resulting height. When I'll have its height more than page height, I'm done. However, this approach will not work in case of long tags, e.g. long paragraph.
Thanks in advance.
EDIT: thanks for your previous answers. I tried to use approach of manual calculating the size of the elements, and encountered one problem which I cannot solve in a good way. This is problem of collapsing margins. What I'm trying to do is to loop through all the paragraphs in my document and sum up results of .outerHeight(true) jQuery call. This should give me the full height of element, including padding, margin and border. And it actually does what it says, but the problem here is that it doesn't take collapsing margins into account. Because of that I end up with wrong overall size (bigger than real one), because browser throws away some of margins (of adjacent paragraphs in my case), but I take them into account.
Any ideas how to solve this other than introducing the algorithm deciding which margins are collapsed and which are not? I think it is ugly...
You could use CSS3 multi-column rules, example: http://www.quirksmode.org/css/multicolumn.html
Or for support in all browsers use a javascript plugin: http://welcome.totheinter.net/columnizer-jquery-plugin/
This plugin even has a multi-page multi-column example: http://welcome.totheinter.net/2009/06/18/dynamic-multi-page-multi-column-newsletter-layout-with-columnizer/
I can think of one framework which seems to do what you need (and a bit more): https://github.com/Treesaver/treesaver
jQuery will give you the height (in pixels) of an element with the height() function.
jQuery("BODY").height() will give you the maximum height of the view port (though only if your content height is >= the height of the BODY - otherwise it will give you the height of how much space the body is taking up in the view port.)
Counting the heights of the P tags (or other tags) seems like a good way to go. I suppose if you want to break up the content of a P tag for large paragraphs, you could define a maximum "breakage" height for the last P tag on a page. You can then break rest of the contents of the P tag by creating a new P tag with jQuery("#the-next-page-id).append(jQuery("<P>"+restOfTheParagraphContent+"</P>"))
Use your own logic to calculate the height of each element in the html body
using jQuery code
$('selector').height();
Using this, you can calculate the height of some html elements and decide how much
elements should be displayed on your device screen.
for more, please visit jQuery Height Documentation
In case anyone still looking for something like this I recently did it using JQuery. It also leaves the first page empty (for title and such):
https://jsfiddle.net/xs31xzvt/
It basically iterates over the movable items and insert them into a new div if the previous div is full.
(function($) {
$(document).ready(formatPages)
function formatPages() {
var container = $('.container');
var subPage = $('.subpage').get(0);
var subPageHeight = subPage.offsetHeight;
var subPageScrollHeight = subPage.scrollHeight;
// See how many pages we'll need
var pages = Math.floor(subPageScrollHeight / subPageHeight) + 1;
//add a new page
var pageCount = 2;
var pageDiv = createPageDiv(pageCount);
var subPageDiv = createSubPageDiv(pageCount);
var addPage = function (){
pageCount++;
pageDiv = createPageDiv(pageCount);
subPageDiv = createSubPageDiv(pageCount);
pageDiv.append(subPageDiv);
container.append(pageDiv);
pageContentHeight = 0;
}
addPage()
container.append(pageDiv);
$('.movable').each(function() {
var element = $(this);
//remove the element
element.detach();
//try to add the element to the current page
if (pageContentHeight + element.get(0).offsetHeight > subPageHeight) {
subPageDiv.append(getFooterDiv().show());
//add a new page
addPage();
}
subPageDiv.append(element);
pageContentHeight += element.get(0).offsetHeight;
});
}
function createPageDiv(pageNum) {
return $('<div/>', {
class: 'page',
id: 'page' + pageNum
});
}
function createSubPageDiv(pageNum) {
return $('<div/>', {
class: 'subpage',
id: 'subpage' + pageNum
});
}
function getFooterDiv() {
return $('.footer').first().clone();
}
}(jQuery));

Categories