IE7 & IE8 javascript print function - javascript

I'm having a javascript issue I can't figure out. I've taken a snippet of code that I got
here and am using it in this page.
The idea is that users can click the 'Print List' button and the listing is copied to a div within a hidden iframe and printed. The printed page contains the the iframe source HTML with the list inserted properly. However, in IE7 & 8, the printed page is the full parent page, not the iframe. The behavior in IE9, Chrome and FF is correct.
I tried debugging the script but I couldn't see where it was going wrong.
Here's the code that the Print List click triggers:
function printSection(id) {
if (document.getElementById('print_frame').contentDocument){
theIframe = document.getElementById('print_frame').contentDocument;
}
else {
theIframe = document.frames['print_frame'].document;
}
var thePrinter = theIframe.getElementById('print_section');
var theCopy = document.getElementById(id);
thePrinter.innerHTML = theCopy.innerHTML;
parent.print_frame.printPage();
}
And here's the printPage() function:
function printPage() {
window.parent.print_frame.focus();
window.print();
}
I'd appreciate any help. Please let me know if you need more information. Thanks so much.

A simpler solution might just be to use CSS media types to hide the content of the page and show an otherwise hidden element for print.
CSS
.print{display:none;}
#media print {
.pagecontainer{display:none;}
.print{display:block;}
}
HTML
<body>
<div class="pagecontainer">
Page content here
</div>
<div class="print">Only show this when printing</div>
</body>

Related

Print function only works after second click

I have this function to print a DIV.
Whenever the page is loaded and I click in a "Print" link I have, the DIV is shown to be printed without CSS.
If I close Chrome's print visualization page and click in the "Print" link again, the DIV has CSS applied.
Any ideas why?
Javascript
function printDiv(divId) {
var printDivCSSpre =
'<link href="/static/assets/vendor/sb-admin-2-1.0.7/bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">' +
'<link href="/static/assets/vendor/sb-admin-2-1.0.7/dist/css/sb-admin-2.css" rel="stylesheet">' +
'<div style="width:1000px; padding-right:20px;">';
var printDivCSSpost = '</div>';
$('body').append('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
$("link").clone().appendTo($("#print_frame").contents().find("head"));
window.frames["print_frame"].document.body.innerHTML =
printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
var windowInstance = window.frames["print_frame"].window;
windowInstance.print();
}
HTML
<a id="print" href="#">
<i class="fa fa-print"></i> Print
</a>
<script>
$('#print').click(function () {
printDiv('report')
})
</script>
<div id="report" class="report">
<p># Generated Table#</p>
</div>
First click:
http://imgur.com/a/Go81Y
Closing the print preview page and clicking again in print
http://imgur.com/a/SCxJF
This happens because when you call your printDiv() function, css is also written using inner HTML and in this scenario CSS is not applied during first click because you wrote CSS to the elements even when they do not exist inside DIV.
The function to work as desired has to write DIV contents first and then CSS should be applied. I would say write css after contents of DIV or load on top of your HTML page and just write DIV contents.
Hope that helps.
Every thing is right just change the sequence. In browser debugger on first click it didn't show 'print_frame' in sources section while in second click it does (I am using chrome devtool).
So load in memory frame with css attributes during onload:
var windowInstance;
$(function(){
$('body').append('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
$("link").clone().appendTo($("#print_frame").contents().find("head"));
windowInstance = window.frames["print_frame"].window;
});
and onClick just append html
$('#print').click(function () {
var divId = 'report';
var printDivCSSpre ='<div id="printReportDiv" style="width:1000px; padding-right:20px;">';
var printDivCSSpost = '</div>';
window.frames["print_frame"].document.body.innerHTML = printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
windowInstance.print();
});
updated jsfiddle
Try this one. The problem mainly arises because the css has not been applied to the page when the print command is initiated. setTimeout is one way to solve it as others have mentioned but it is really not possible to predict how much delay you will need. Slow internet connections will require high delays before you fire the print statement. The following code, however, only fires the print event after the css has been properly applied to the iframe.
$('#print').click(function () {
if($("#print_frame").length == 0) {
$('#report').after('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
}
var $head = $("#print_frame").contents().find("head");
// for now for ease I will just empty head
// ideally you would want to check if this is not empty
// append css only if empty
$head.empty();
$.ajax({
url : "https://dl.dropboxusercontent.com/u/7760475/reports.css",
dataType: "text",
success : function (reports) {
// grab css and apply its content to the iframe document
$head.append('<style>'+reports+'</style>');
$.ajax({
url : "https://dl.dropboxusercontent.com/u/7760475/bootstrap.css",
dataType: "text",
success : function (bootstrap) {
// grab another css and apply its content to the iframe document
// there may be better ways to load both css files at once but this works fine too
$head.append('<style>'+bootstrap+'</style>');
// css has been applied
// clone your div and print
var $body = $("#print_frame").contents().find('body');
// empty for ease
// but later append content only if empty
$body.empty();
$("#report").clone().appendTo($body);
$('#print_frame').get(0).contentWindow.print();
}
});
}
});
});
Use inline CSS instead.
Reason: When we PRINT or save as PDF if fails to fetch external css Files, So we have to use Inline css.
edited your file please see: jsfiddle.net/ytzcwykz/18/
As other people mentioned it is hard to see your problem without seeing the working example of a problem, but just guessing from the code:
Browser is not able to load the CSS before your print() call.
Browser is not able to render the CSS before your print() call.
Keeping that in mind changing your JS function that way might do the trick
function printDiv(divId) {
$("link").clone().appendTo($("#print_frame").contents().find("head"));
window.frames["print_frame"].document.body.innerHTML =
printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
var windowInstance = window.frames["print_frame"].window;
setTimeout(function() {
windowInstance.print();
}, 0);
}
The idea behind this function is to let browser execute it's code after we added changed the HTML/CSS code in the window - see Why is setTimeout(fn, 0) sometimes useful?
WARNING: this approach is not tested for your particular problem, and it might also not work because we escape/leave the mouse-click call-stack, calling print() method might be not possible out of user-interaction stack.
UPDATE: after looking in the posted jsfiddle - my assumption was correct, the browser needs some time to load and render the CSS, that is why calling the print() right after changing iframe contents doesn't give the desired result. There are 3.5 ways to solve that:
Use events to identify when iframe's document and window has finished loading and rendering. I tried two approaches, and failed so far, need to read docs more carefully about when document and window are behiving during the loading sequence:
we can do that from outside of iframe, i.e. listen to events of iframe element and it's children
we can do that from inside of iframe, i.e. add little javascript snippet inside which will send a message to the parent window when loading is done.
Consider forming the print result different, how about print style-sheets? I.e. add one more style sheet with print-media query to the parent doc and just call print on it?
Consider forming an iframe which is already loaded and ready to be printed, but replace just the table contents inside it.
As others mentioned, The problem here is that the CSS files used are external resources and browser takes time to download and cache it locally. Once it is cached, it would serve faster and that's why it works fine from the second click.
As Anton mentioned, setTimeout is the key here! You may probably increase the timeout seconds to make that work. I tried setting it to 500ms and that worked,
setTimeout(function(){windowInstance.print();},500);

Javascript overwrites data on screen and refreshes page

I have been working on a project that I just need to print the contents of a hidden div. The below solution works fine, but replaces the page contents with the div then calls the print of the window and then replaces the page with the original contents. This is fine, but when I click on the page after this or try to print again, the page refreshes.
Is there a way, without opening a new window to print the contents of a div and the page still be functional?
$scope.printDiv = function(printable) {
var restorePage = document.body.innerHTML;
var printContent = document.getElementById(printable).innerHTML;
document.body.innerHTML = "<html><head><title></title></head><body>" + printContent + "</body>";
window.print();
document.body.innerHTML = restorePage;
};
I had created a directive that did something much like this. It involves creating a new window, populating it with the HTML you want printed, printing that window, and then finally closing.
The code looks like the following:
$scope.printPage = function() {
var pageToPrint = $window.open('', 'Print Page', 'width=800, height=600');
pageToPrint.document.write(angular.element(pageHtml).html());
pageToPrint.document.close();
pageToPrint.focus();
pageToPrint.print();
pageToPrint.close();
}
This works in all of the browsers and cleanly closes everything out once the user finishes with the print dialog window.
You can do it with CSS: https://stackoverflow.com/a/356123/1516112
When the user click on your button, wrap your entire page inside a div using the .no-print class. Next add your content in another div next to the previous div. Call print() and restore your page. It should works.
See a similar question that I found: AJAX - Print Page Content
It seems the answer of Matt Razza is what You are looking for.
If you're trying to print invisible content you could use two
different css files for the different media (screen vs print) where
you hide/unhide the required content via display: none; and then
spawn the print dialog via window.print().
<link rel="stylesheet" type="text/css" href="theme1.css" media="screen" />
<link rel="stylesheet" type="text/css" href="theme2.css" media="print" />
<div class="hidden_on_page">YOU CAN'T SEE ME BUT YOU CAN PRINT ME!</div>
<div class="on_page">YOU CAN SEE ME BUT YOU CAN'T PRINT ME</div>
Then in theme1.css:
.hidden_on_page { display: none; }
theme 2.css:
.on_page { display: none; }
And you would trigger the print dialog to spawn when required via:
window.print();

How to make an iframe auto-resize along with the dynamic changes on its content?

I have this js code I searched on auto-resizing iframe height with its content. It does what the user who posted this says it does. However, I now have this problem with dynamic content within the iframe.
The js code I have works only with the regular content of the page but not when there are dynamic changes going on within. For example, displaying texts through ajax call.
I've tried searching for other solutions to this but others did not work as well as what this code can do.
I'm hoping that there's someone who could help me update the code to meet what I currently need. I'm not very familiar with jquery/javascript to do this on my own. Thank you in advance! :)
This is the JS code:
function setIframeHeight(iframeId) {
var ifDoc, ifRef = document.getElementById(iframeId);
try {
ifDoc = ifRef.contentWindow.document.documentElement;
} catch (e) {
try {
ifDoc = ifRef.contentDocument.documentElement;
} catch (ee) {}
}
if (ifDoc) {
ifRef.height = 1;
ifRef.height = ifDoc.scrollHeight;
/* For width resize, enable below. */
//ifRef.width = 1;
//ifRef.width = ifDoc.scrollWidth;
}
}
I found this other code which enables iframe adapting to its dynamic content but I do not know how to make the code above and this work together. Please help me.
var iframe = document.getElementById("ifr").contentWindow;
iframe.$(".toggle_div").bind("change", function () {
$("#ifr").css({
height: iframe.$("body").outerHeight()
});
});
To summarize, I need a code that autoresizes iframe with its content and will autoresize again if there are changes on the size of the content.
The problem is that your page doesn't have any trigger indicating to resize when the iframe body resizes.
There also (as far as I know) isn't anything built into javascript that lets you watch for changes in an elements height.
You have two options.
If you are the owner of the iframe content, you can put a script in that page which can call to it's parent window telling the parent to run your resize script, or you can run a function which checks for changes say every second or so.
For the first method, you can follow the answer from here Can events fired from an iframe be handled by elements in its parent?
Otherwise just do a
setTimeout(function(){
$("#ifr").css({
height: iframe.$("body").outerHeight()
});
},1000);
function adjustMyFrameHeight()
{
var frame = getElement("myFrame");
var frameDoc = getIFrameDocument("myFrame");
frame.height = frameDoc.body.offsetHeight;
}
call this method on your iframe onload event and replace mtFrame to your iframe Id

Why doesn't setting frame src by js show the display source?

Based on a JS condition, I want either of the 2 things to happen;
Either to show a frame on page
OR
Show a link "Show pdf" on page..
Show pdf
Now while I know how to do a Show/Hide based on the JS condition, my question is
In case 2nd condition is satisfied, not only do I want to hide the frame thing, BUT ensure that it is not loaded in the background as well...
I think using show/hide will not stop it from loading the pdf in the background..
So my question is how can I acheive that using Javascript?
**********Here is what I am trying**********
if(isiPad)
{
$('#content').attr('src','ipad_frame.html');
}
else
{
$('#content').attr('src','xyz.pdf');
}
And in the html, I have
<frame src="#" title="Content Frame" name="content" id="content" />
Will this work fine? For some reasons, I just tested it and even though it goes in the if/else part, it does not show the relevant content..
Why not add the elements dynamically in script to a container element? Something like (assuming you're using jQuery):
if(condition)
{
$('#container').html('<html for frame>');
}
else
{
$('#container').html('<html for pdf>');
}
This will ensure only the item that you want to load is loaded.
Rather than show/hide, you could use the DOM to modify the contents of the page:
<div id="frameWillBeHere">
</div>
<script language="javascript">
var f = document.getElementById('frameWillBeHere');
if (whatever) {
f.innerHTML = '<iframe>pdf file</iframe>';
}
else {
f.innerHTML = 'something else';
}
</script>
You can also make that script respond to an event, so that the frame will appear when needed. There is some work to do so that the frame appearing in your page doesn't completely break your layout.

Why does my JS mobile nav work on all my pages but one?

I'm building a website, and I have a mobile dropdown menu that is controlled by JS (and appears with #media queries for devices under 400px). My website is jeffarries.com (and the page I'm talking about is live there), the mobile nav works on all of my other pages, but not my Politics page. The thing that isn't working is the bars that open and close the nav dropdown don't rotate and the body isn't set to position: fixed;. Why does my JS work on all my page but Politics?
Thanks!
P.S. I can provide code, but it's like 250+ line and in different files, so I think it would be best if you view it on my website. (I'm not trying to sound lazy, so if you want the code, just ask and I will provide it)
Why does my JS mobile nav work on all my pages but one?
Because you have a javascript error!
Check your browsers console and you will see it:
TypeError: null is not an object (evaluating 'document.getElementById("javascript_warning").style')
If you look on line 331 of your politics.js file you will see the following function:
// Hides javascript warning message
function myFunction() {
document.getElementById("javascript_warning").style.display = "none";
}
This is what is causing the error because document.getElementById("javascript_warning") is null and you are trying to call style on it.
Make sure that the element exists first e.g.
// Hides javascript warning message
function myFunction() {
var elem = document.getElementById("javascript_warning");
if (elem != null) {
elem.style.display = "none"
}
};
A quick fix is:
Remove this line
var body = document.getElementsByTagName("BODY")[0];
Replace 'body' with 'document.body' in these lines:
body.style.position = "fixed";
body.style.position = "";
You should correct other errors appearing in console aswell.

Categories

Resources