Insert a page break if the height of a div does not fit in print media? - css

I am dynamically creating elements on a web page which I want to print. I want a page break if the element can't fit in the rest of the A4 size paper.
Example is this question: Force an element to take exactly half of available height in print media
In the picture, A broken element is appearing on first page, which should actually go on the second page.
How can I force a page break if the element does not fit in this page.
**What I tried: **
I tried to use css page-breakafter` property, with the following code:
$(document).ready(function(){
$(".row").each(function(){
if($(this).height()>$(document).height()/2){
$(this).after('<div style="page-break-after:always"></div>');
}
});
});
But it does not work.
Here is a JsFiddle

I noticed in your fiddle that you have applied page breaks only after a few rows. The problem with your jQuery code is that, the $(document).height() will return a huge value compared to each row. In your case, document height = 3861 while each row is only 537. Hence 537 is never greater than 3861/2. Revisit the exact condition you need to apply the page break. I tried window.height instead and it works.
Note: You can only see the difference in print preview
EDIT:
Could you remove all the page break div's you manually added and try the below script.
What I tried is to capture the previous element height and then calculate if he page break is necessary.
For this purpose, I have kept a maxHeight of the document to be 1024 considering how much an A4 sheet can take up. Feel free to adjust the maxHeight according to your paper size.
$(document).ready(function(){
var prevRowHeight = 0;
$(".row").each(function(){
// console.log($(this).height());
var maxHeight = 1024;
var eachRowHeight = $(this).height();
if((prevRowHeight + eachRowHeight) > maxHeight){
$(this).before('<div style="page-break-after:always"></div>');
console.log("add page break before");
}
prevRowHeight = $(this).height();
});
});

Previous answer was good but there is a bug. You must need total_height. Please Check this I think this code help you. I use this code for a hospital management project for printing system. Thank you.
jQuery(document).ready(function(){
var prevRowHeight = 0;
var total_height = 0;
jQuery(".row").each(function(){
// console.log($(this).height());
var maxHeight = 1000;
var eachRowHeight = jQuery(this).height();
total_height += prevRowHeight + eachRowHeight;
alert('now : '+total_height +' , Was: '+ prevRowHeight);
if(total_height > maxHeight){
jQuery(this).before('<div style="page-break-after:always"></div>');
console.log("add page break before");
now_height = 0;
}
prevRowHeight = jQuery(this).height();
});
});

Related

Automatically change image-url by 1 for next div?

I'm making a bunch of stacked divs that will expand when moused-over to show an image, but I have a lot of images.
Is there a way in CSS or JS (I don't really know anything about JS) to have each div automatically use the next image in a folder? ex: the images are named map1.jpg, map2.jpg ... map91.jpg. and be able to use the same background-image:url but have something telling it to add 1 to the next image for each new div so I don't have to manually specify 90+ different images.
I hope I was able to explain that well enough. Thanks =)
In CSS this is impossible, cause you can't concatenate the url path for background-image.
in javascript this is pretty simple, using jQuery you can simply load all div you need when body is ready:
// on page load
$(document).ready(function(){
// 10 images to div #image-board
for(var i=0; i<10; i++){
// create a div with image #i
$('#image-board').append('<div><img src="my/collection/folder/Image'+i+'.jpg"></div>');
}
});
don't forget to create in your HTML page a <div id="image-board"></div> where all images will be listed to
I'll try to include lots of detail since you say you're unfamiliar with JavaScript. When you say stacked divs, I assume you mean one inside another. Start with a div with appropriate id and background in your html <div id="div0" style="background-image:url('map0.jpg')"></div> Here's some Javascript using jQuery (a very common javascript library you can include with a script tag) that will add a new div inside your first div with the updated url name.
for (var i = 0; i < number_of_images - 1; i++) {
var oldId = '#div' + i;
var newId = 'div' + (i + 1);
var newUrl = 'map'+(i+1)+'.jpg';
var newdiv = '<div id="' + newId + '" style="background-image:url('+newUrl+')></div>';
$(oldId).append(newdiv);
}
The for loop will go over every image, then a string is created in a series of concatenations that becomes your updated div. The '$' searches for the DOM element with that id, then adds the new div inside it. If by stacked you meant a new div underneath but not contained by the previous div, use .insertAfter instead of .append. Assuming your webpage can reach all of the images, this should work. Also notice I've 0 indexed this (the standard in Javascript) but your question referred to map1 as the first map. If you have already named these maps, you may need to re-index the for loop to 1.

Twitter bootstrap carousel with pictures that are not uniform

Let me start with i am sorry for the long post.
I'm attempting to use the bootstrap carousel and unfortunately the pictures i have been given are NOT uniform. for example some are 100x200, doe are 150x100, etc. The aspect ratios are different, letter vs landscape. Ive attempted a number of things, including the using the following helper function on load of each of my images in the Carousel:
function ScaleImage(srcwidth, srcheight, targetwidth, targetheight, fLetterBox) {
var result = { width: 0, height: 0, fScaleToTargetWidth: true };
if ((srcwidth <= 0) || (srcheight <= 0) || (targetwidth <= 0) || (targetheight <= 0)) {
return result;
}
// scale to the target width
var scaleX1 = targetwidth;
var scaleY1 = (srcheight * targetwidth) / srcwidth;
// scale to the target height
var scaleX2 = (srcwidth * targetheight) / srcheight;
var scaleY2 = targetheight;
// now figure out which one we should use
var fScaleOnWidth = (scaleX2 > targetwidth);
if (fScaleOnWidth) {
fScaleOnWidth = fLetterBox;
}
else {
fScaleOnWidth = !fLetterBox;
}
if (fScaleOnWidth) {
result.width = Math.floor(scaleX1);
result.height = Math.floor(scaleY1);
result.fScaleToTargetWidth = true;
}
else {
result.width = Math.floor(scaleX2);
result.height = Math.floor(scaleY2);
result.fScaleToTargetWidth = false;
}
result.targetleft = Math.floor((targetwidth - result.width) / 2);
result.targettop = Math.floor((targetheight - result.height) / 2);
return result;
}
function OnImageLoad(evt) {
var img = evt.currentTarget;
// what's the size of this image and it's parent
var w = $(img).prop('naturalWidth');
var h = $(img).prop('naturalHeight');
//var tw = $(img).parent().width();
//var th = $(img).parent().height();
var tw = $(img).parent().parent().parent().parent().width();
var th = $(img).parent().parent().parent().parent().height();
// compute the new size and offsets
var result = ScaleImage(w, h, tw, th, true);
// adjust the image coordinates and size
img.width = result.width;
img.height = result.height;
$(img).css("left", result.targetleft);
$(img).css("top", result.targettop);
}
and using the following for each of my images for the carousel
<img src="~/Images/Img1_Tall.jpg" alt="Tall" id="firstImage" onload="OnImageLoad(event);" />
and for the FIRST image in the carousel it works great, but each one after that they seem to just end up their natural size and are horizontally centered but are just against the top boarder of the carousel.
I've even changed the "onload" to pass the values of the length and width of the image but that didn't work either, in debug it seems only the first image kicks off the "onload" event.
the effect i am going for is if the ratio of the container is 3:4 and the ratio of the image is 1:2, the image stretch to meet the left and right edges and would center vertically and have letter box above and below, but the container does not change so that the navigation buttons of the carousel do not move. if the image is 2:1, the image would stretch to meet the top and bottom centered horizontally with letterboxes on the right and left, again keeping the navigation buttons unmoved.
any help would be appreciated... including:
what you are trying to do is crazy
do you want to do something like http://jsbin.com/zotelasa/1 . With that code I can get the active items w,h or any other variables you used in your code to run scale image. Because of parent.parent codes it applies to carousels main divs but you can set your own container.
The quick and dirty solution would be to resize the images using an image editor, and save the properly-sized images to a folder named eg carousel_images. Then whenever you get new content you simply run the image through your editor. With a carousel you're most likely dealing with a number of images in the several to dozens range and not hundreds or thousands.
A more complicated solution is explain to your image provider that you need everything one size. The images aren't going to look right if you're stretching and skewing them on the fly, and you can show them an image with the aspect ratios wrong to explain what you mean.
Finally, as a technical solution, I would try to find out why your image resizer is only being run on the first image. From the sound of it, other images just aren't being run through your function. I think that the technical solution should be a last resort in this case because, like I said, the end results are just not going to be as good. You should at a minimum, if possible, handle each image by hand to make sure the result is adequate.
...And the answer is a little long too...
• I assume that the width’s image’s parent is a constant, and while you don’t change the width’s viewport that must remain.
A-. Get the width’s image’s parent…
(Because the id attribute I took the grand parent’s parameter, that is (must be) the same than the parent’s one).
B-. With the below value deduce the height’s image’s parent, including the preferred ratio (in this case 16x9…
C-. … And with this, set the images’ parents height collection (all the elements with class=”item”).
D-. In order to conserve your carousel’s responsive characteristic, you must add the $F_getAdjustImagesParents function to the window resize event.
E-. Set the slide’s images position to absolute (Note: That must be via JQuery because if you do it in Css the bootstrap carousel will not display correctly. I did it with a new class for the images ('myCarouselImgs').
• Bootstrap carousel’s event 'slide.bs.carousel' and 'slid.bs.carousel'.
As you know, after the ‘click’ event, the slide.bs.carousel event is one of the firsts events that imply the change from the present slide to the next one; while the 'slid.bs.carousel' one is the end of the process.
F-. In the first one (slide.bs.carousel event), using the ‘relatedTarget’ variable of the Bootstrap’s plugin, the item’s id attribute and a item’s data attribute, get the number of the next item (ensure that these last ones -id attribute and data attribute- be present).
G-. In the second one, 'slid.bs.carousel', get the image’s size. For that you need to identify the implied image. I gave an id to each one. With this and the value obtained in previus step, it can do it.
H-. Well, now you already have the four values required for the ScaleImage function. You can call it…
I-. … And apply the result with some effect
var $parentImgW = ' '
var $parentImgH = ' ';
var $myCarousel = $('#myCarousel')
var $carouseItems = $('.item');
function $F_getAdjustImagesParents(){
$parentImgW = $myCarousel.width(); // A
$parentImgH = ($parentImgW*9)/16; // B
$carouseItems.height($parentImgH+'px').css('max-height',$parentImgH+'px'); //C
console.log('$parentImgW ====> '+$parentImgW);
console.log('$parentImgH ====> '+$parentImgH)
};
$F_getAdjustImagesParents();
$(window).on('resize',function(){ // D
$F_getAdjustImagesParents();
});
$('.myCarouselImgs').css('position','absolute'); // E
$myCarousel.on('slide.bs.carousel', function(event) {// The slide’s change process starts
var $slideNum = $("#"+event.relatedTarget.id).data('slide_num'); // F
console.log('$lideNum ====> '+$slideNum)
$myCarousel.on('slid.bs.carousel', function(event) {//The slide’s change process ends
var $imgW = $('#myCarouselSlideImage'+$slideNum).width(); //G
var $imgH = $('#myCarouselSlideImage'+$slideNum).height(); //G
console.log('$imgW ====> '+$imgW);
console.log('$imgH ====> '+$imgH);
var $result = '';
$result = ScaleImage($imgW, $imgH, $parentImgW, $parentImgH, true); //H
console.log('$result.width ====> '+$result.width);
console.log('$result.height ====> '+$result.height);
console.log('$result.targetleft ====> '+$result.targetleft);
console.log('$result.targettop ====> '+$result.targettop);
$('#myCarouselSlideImage'+$slideNum).animate({ // I
width:$result.width+'px',
height:$result.height+'px',
left:$result.targetleft+'px',
top:$result.targettop+'px' },
300);
});
});
See it runnig at https://jsfiddle.net/nd90r1ht/57/ or at https://jsfiddle.net/omarlin25/nd90r1ht/59/

PhantomJS: Webkit-Transform scale causes page to flow outside viewport

I'm trying to generate large png screenshots of web pages using PhantomJS, which is built on webkit. I have the application generating screenshots just fine (using their raster.js example.) But, I want the text to be larger (rather than 12-16px) - I don't care about the images becoming grainy. I thought that I could simply scale/zoom the webpage doing something like:
document.documentElement.style.webkitTransform = "scale(2.0)";
But that causes the content of the page to escape the viewport. You can see this if you evaluate that line of code in Chrome. Is it possible to scale a whole web page (duplicating "Ctrl +" functionality of the browser) in JavaScript/Phantom.js?
My current phantom.js script looks like:
var page = new WebPage(),
address, output, size;
if (phantom.args.length < 2 || phantom.args.length > 3) {
console.log('Usage: rasterize.js URL filename');
phantom.exit();
} else {
address = phantom.args[0];
output = phantom.args[1];
page.viewportSize = { width: 1280, height: 1024 };
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
} else {
page.evaluate(function () {
document.body.style.webkitTransform = "scale(2.0)";
});
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 200);
}
});
}
Try
page.zoomFactor=2.0;
The webkitTransform CSS property is not going to do what you want, with or without setting the origin. For one thing, it does not change the dimensions of elements (ie, no relayout occurs, the element(s) are zoomed within their current bounding boxes).
Update
You forgot to set the CSS transform-origin property, so your content expands half up and half down (the default is 50% 50%) and the upper part escapes.
So set it to 0% 0% to get the transform happen only down and right:
document.body.style.webkitTransformOrigin = "0% 0%";
You will also have to set the body width to 50% to avoid it ending twice as large as your viewport:
document.body.style.width = "50%";
Old answer - disregard
This resolves only vertical alignment
Ok, the scaling goes up and down, but the viewport extends only down. The fix fortunately is easy: move your content down of half its height.
Use this as your doubling function and you'll be fine:
page.evaluate(function() {
var h = $('body').height();
$('body').css('position', 'relative');
$('body').css('top', h/2 + 'px');
$('body').css('-webkit-transform', 'scale(2.0)');
});
Be aware anyway that getBoundingClientRect() and page.clipRect behaves weirdly when dealing with this transform.

Codemirror cursor position offset

I'm using code mirror to display, highlight and edit xml in a web page but I am having a problem with the cursor position being offset from the insert position so that if you delete a character from where the blinking cursor is, a character before the one you would expect gets deleted instead. I am assuming its a css clash with my current page because it works well outside my page, but cant find the clash anywhere. Has anyone had similar issues or know what to do?
Further investigation shows that the page had padding set on all divs embedded in fieldsets which was the cause of the problem.
The following lines fixed the issue for me:
.CodeMirror pre {
white-space: pre-wrap;
word-break: break-all;
word-wrap: break-word;
}
I'm using lineWrapping: true in my CodeMirror configuration. Setting that to false works as well.
Be careful using zoom in your CSS with CodeMirror.
I used zoom in body and removing that worked for me.
This issue often happened to me after resizing a parent container. What helped was:
editor.setSize("100%", "100%");
editor.focus();
in the end of a resize event handler.
Sometimes, also, below italic or bold -containing lines (depending on your OS and browser), cursor has a wrong vertical position up to 90% of a line. It can be easily fixed by setting, e.g.
.CodeMirror pre {
height:15px;
}
anywhere in your CSS stylesheets. This also provides you with a way to control line height, if you find lines of code showing too close to each other.
For some reason the white spaces when indention is enabled were not treated correctly when calculating the line size. Replacing measureLine function with the following in codemirror.js did the trick for me:
function measureLine(cm, line) {
// First look in the cache
var cached = findCachedMeasurement(cm, line);
if (cached) return cached.measure;
// Failing that, recompute and store result in cache
var measure = measureLineInner(cm, line);
var origL;
var origR;
var lastR ="";
for (var mes in measure) {
origL = measure[mes].left;
origR = measure[mes].right;
if (lastR != "") {
measure[mes].left = lastR;
measure[mes].right = lastR + (origR - origL);
}
if (origL == origR) {
measure[mes].right = measure[mes].right + 8;
}
lastR = measure[mes].right;
}
var cache = cm.display.measureLineCache;
var memo = {
text: line.text,
width: cm.display.scroller.clientWidth,
markedSpans: line.markedSpans,
measure: measure,
classes: line.textClass + "|" + line.bgClass + "|" + line.wrapClass
};
if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo;
else cache.push(memo);
return measure;
}

Autosize Text Area (Multiline asp:TextBox)

I have a MultiLine asp:Textbox (a standard html textarea for those non-asp people) that I want to be auto-sized to fit all it's content only through css. The reason for this is that I want it to be of a specified height in the web browser, with scrolling enabled.
I have implemented a print style sheet however and want all text located in the textarea to be displayed when printed with no overflow hidden.
I can manually specify the height of the textarea in the print.css file problem with this being that the fields are optional and a 350px blank box is not optimal and there is always the possibility of a larger amount of text than this...
I have tried using :
height: auto;
height: 100%;
In IE and Firefox respectively yet these seem to be overridden by the presence of a specified number of rows in the html mark-up for the form which must be generated by .NET when you do not specify a height on the asp:Textbox tag, this seems to only accept numercial measurements such as px em etc...
Any ideas?
What you are asking for (a css solution) is not possible.
The content of the textarea is not html elements, so it can not be used by css to calculate the size of the textarea.
The only thing that could work would be Javascript, e.g. reading the scrollHeight property and use that to set the height of the element. Still the scrollHeight property is non-standard, so it might not work in all browsers.
jQuery or a javascript function to find and make textboxes bigger might be the best solution - at least thats what i found
we use this set of functions and call clean form after the page is loaded (i know this isnt the best solution right here and am working to transfer to a jQuery solution that is more elegant) - one note make sure your textareas have rows and cols specified or it doesnt work right.
function countLines(strtocount, cols)
{
var hard_lines = 1;
var last = 0;
while (true)
{
last = strtocount.indexOf("\n", last + 1);
hard_lines++;
if (last == -1) break;
}
var soft_lines = Math.round(strtocount.length / (cols - 1));
var hard = eval("hard_lines " + unescape("%3e") + "soft_lines;");
if (hard) soft_lines = hard_lines; return soft_lines;
}
function cleanForm()
{
var the_form = document.forms[0];
for (var i = 0, il = the_form.length; i < il; i++)
{
if (!the_form[i]) continue;
if (typeof the_form[i].rows != "number") continue;
the_form[i].rows = countLines(the_form[i].value, the_form[i].cols) + 1;
}
setTimeout("cleanForm();", 3000);
}
If you set rows to be a ridiculously high number the CSS height rule should override it on the screen.
Then in the print stylesheet just set height to auto. This might result in some big blank space where all the available rows haven't been filled up, but at least all text will be visible.
give jQuery's autogrow() a go #
http://plugins.jquery.com/project/autogrow

Resources