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

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.

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);

How to run code only when iframe loaded

I have been battling with this issue for a few days now and finally found a partial solution but I think it could be improved.
In my project, I have a series of iframes that contain videos. When a link is clicked are displayed with a slide transition and when the link is clicked again the video stops and the span containing the iframe is hidden also with a transition.
This is achieved by adding and removing a css class of "open" that has a height and a transition in it. In addition to this I have an event listener that collapses the containing span also when the video finishes. All this works fine and to save time I am not posting the code.
The issue I was having was with slow page loading times, so I removed the src attribute for the iframes from the html and moved it to my js file and assigned it only after the click is performed. This wasn't working and I realised I needed the iframe to fully load before running the rest of the code inside the "click" method. So I delayed this part of the code by 100ms.
All this works, but I feel it would be better to have the rest of the code run not after a 100ms lapse but when the iframe is loaded (in case page viewed by slower computers). Not sure how to do this.
Here is the code as it stands now:
var player;
var frame = $("#frame");
frame.bind("load", function () {
player = $(this).contents().find("#myVid");
player.on('ended', function () {
frame.removeClass("open");
});
});
$("#clickableLink").click(function(){
if (frame.hasClass("open")) {
frame.removeClass("open");
frame.contents().find('#myVid').get(0).pause();
} else {
function delayed(){
frame.addClass("open");
frame.contents().find('#myVid').get(0).play();
}
frame.attr("src","iframe.html");
setTimeout(delayed, 100);
}
});
Fairly new to development so I am looking for the simplest way to do this. Any help appreciated.
Here is a super simple example of calling code when the iframe has loaded. Check out the onload attribute of the iframe tag:
<head>
<script>
function frameLoaded() {
alert('frame loaded!');
};
</script>
</head>
<body>
<iframe id="frame" src="https://en.wikipedia.org/wiki/HTML_element#Frames" onload="frameLoaded(this)" />
</body>

Panel only showing on specific page

I need a working javascript code which shows a certain panel only on one specific page on my website and hides it on the rest. It's a forum-esque setup.
Here's what I got so far.
<script type="text/javascript">
function ShowPanel()
{
if(document.location.href == "http://www.exampleurl.com")
{document.getElementById("panel").style.display = "block";}
else
{document.getElementById("panel").style.display = "none";}
}
</script>
<div id="panel" onload="ShowPanel">
Example text.
</div>
According to the example code I've looked up, all of this seems to be reasonable, but obviously there's an error somewhere. Nothing happens.
Thanks for checking!
The problem is that the onload event cannot be used on a DIV element. onload can only be used on the document body or an external resource (iframe, image, scripts).
Your best bet is to place your JavaScript at the bottom of the page instead.
e.g.
<div id="panel">
Example text.
</div>
<script language="JavaScript">
if(document.location.href == "http://www.exampleurl.com"){
document.getElementById("panel").style.display = "block";
}
else {
document.getElementById("panel").style.display = "none";
}
</script>
Check what the document.location.href really is on the page by typing it into your console (F12, usually). For instance, most browsers will add the trailing slash onto a server name even if there isn't one in the URL. The match has to be exact for your code to work as written.
Another options is to compare document.location.pathname, which will have everything after the server name. If you want to make a case insensitive compare, you can use document.location.pathname.toLowerCase().

IE7 & IE8 javascript print function

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>

Javascript problem with iframe that's hidden before loaded

I have a page that contains an iframe that gets loaded using Javascript:
index.html
<iframe id="myFrame" width="800" height="600" style="display: none;"></iframe>
<div id="loader"><!-- some loading indicator --></div>
<script type="text/javascript">
function someFunction() {
var myFrame = document.getElementById('myFrame');
var loader = document.getElementById('loader');
loader.style.display = 'block';
myFrame.src = 'myFrame.html';
myFrame.onload = function() {
myFrame.style.display = 'block';
loader.style.display = 'none';
};
}
</script>
The page that gets loaded in the iframe contains some Javascript logic which calculates the sizes of certain elements for the purposes of adding a JS driven scrollbar (jScrollPane + jQuery Dimensions).
myFrame.html
<div id="scrollingElement" style="overflow: auto;">
<div id="several"></div>
<div id="child"></div>
<div id="elements"></div>
</div>
<script type="text/javascript">
$(document).load(function() {
$('#scrollingElement').jScrollPane();
});
</script>
This works in Chrome (and probably other Webkit browsers), but fails in Firefox and IE because at the time jScrollPane gets called, all the elements are still invisble and jQuery Dimensions is unable to determine any element's dimensions.
Is there a way to make sure my iframe is visible before $(document).ready(...) gets called? Other than using setTimeout to delay jScrollPane, which is something I definitely want to avoid.
Some browsers assume that when "display:none" is applied to replaced elements (like Flash or an iframe) the visual info for that element is no longer needed. So, if the element is later displayed by the CSS, the browser will actually recreate the visual data form scratch.
I imagine that having the iframe default to "display:none;" makes the browser skip the rendering of the HTML so the tags don't have any dimensions. I would set the visibility to "hidden" or position it off the page rather than use "display:none;".
Good luck.
instead of making the iframe invisible by using display:none, you could try to...
... set visibility:hidden
... set position:absolute; top:-600px;
... set opacity:0
or something else that makes jQuery "see" the objects but not the user (and reset the used css-attributes in your myFrame.onload function).
visibility:collapse;
display:hidden;
height:0px;
Will work to get rid of white space too..
The iframe will also load..
Hidden iframes are a huge security issue. Probably best to try to find another way to accomplish what you want, if it is legitimate, because hopefully future browsers will get rid of this feature altogether. http://blog.opendns.com/2012/07/10/opendns-security-team-blackhole-exploit/

Categories

Resources