I'm trying to generate a pop-up window with a printable version of a small portion of the main window. I'm using Meteor, so the HTML and CSS files are all programmatically generated.
What I'd like to do is use Javascript to read all the linked CSS files in the parent window and append them to the child window.
var childWindow = window.open("", "_blank", "width=350,height=150");
var childDoc = childWindow.document;
var childHead = childDoc.getElementsByTagName("head")[0];
$('link').each(function(index,element){
childLink = childDoc.createElement("link");
childLink.rel = "stylesheet";
childLink.href = element.href;
childHead.appendChild(childLink);
});
childDoc.write(myHtml);
But its not working. It appears that childHead is referring to the head of the parent document, not the child. I'm not sure if this is a security thing I'm running afoul of or just have a mistake in the code.
Any ideas what I'm doing wrong?
I'm doing a very similar thing on one of my pages. I just use the 'parent' page to write everything and it works fine. Here is how it works for me. See this fiddle in action.
You'll notice that it only prints the stuff from the printMe div. Also, the printed page has all the same exact scripts and styles that the parent page does.
some stuff NOT to print
<div id="printMe" class="ui-selectable-helper">
I should be printed, but not the other stuff.
</div>
more stuff NOT to print
$(function(){
var printWindow = window.open('', 'printWin', 'height=600, width=900, toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, directories=no, status=no');
//create a new HEAD with the exact same content as the main page
var writeMe = ('<body><head>' + $('head').html() + '</head><html>');
//grab the content of the printMe div and use it on the print page
writeMe += ("<div>" + $('#printMe')[0].outerHTML + "</div>");
writeMe += ('</html></body>');
printWindow.document.write(writeMe);
printWindow.document.close();
printWindow.focus();
printWindow.print();
//you might even use this next line if you want the 'popup' window to go away as soon as they have finished printing.
//printWindow.close();
});
Note: I am just using the class="ui-selectable-helper" to show you that indeed the CSS pages are transferring properly to the new popup window.
What ended up working for me was appending something to the body with childDoc.write(myHtml);
Previous to this, the CSS would not load, but once I actually passed in a few divs, the CSS showed up without any other modifications.
Related
I generate some telerik reports on a page which I would like to print when the user clicks "Print". I would like to have a popup window which has the same content as the original report with a print dialog. My current approach is to just copy over the head element using document.write. The problem is that since the head element contains script src which loads external script (and also css loads), when the print dialog appears, the pages are blank. I would like to ensure all the content is loaded first on this new page before print dialog is triggered. How can I do this? Below is my code:
function printElem(elem) {
var mywindow = window.open('', 'PRINT', 'height=600,width=800');
mywindow.document.write('<html><head>' + document.head.innerHTML + '</head><body>');
mywindow.document.write('<h1>' + document.title + '</h1>');
mywindow.document.write(document.getElementById(elem).innerHTML);
mywindow.document.write('</body></html>');
mywindow.print();
return true;
}
Unfortunately, there's no way to build up a page that you'll reveal with window.open. You have two options.
First, you could display a loading view that will be hidden once all the other elements have loaded. This is perhaps the most elegant solution if you're committed to opening another popup.
<div id="loader"><img src="loading.gif /></div>
<div id="content" style="display:none">Stuff to print</div>
<script>
<!-- I know jQuery is taboo nowadays, but you get the idea -->
$(function() {
$('#loader').hide();
$('#pagecontent').show();
});
</script>
Another trick is to write the content and close the window immediately afterward. (I'm not certain if this works on all browsers.)
var css = document.getElementById('the-stylesheet');
var content = document.getElementById('the-content');
var mywindow = window.open('', 'PRINT', 'height=600,width=800');
mywindow.document.write(content.innerHTML);
mywindow.document.close();
mywindow.document.head.appendChild(css);
css.addEventListener('load', function () {
mywindow.focus();
mywindow.print();
});
If you're willing to forgo a popup, another trick would be to use print specific styling on the page.
<style>
#media print {
/* Hide everything you don't need here */
}
</style>
You can use onload event on the new window.
function printElem(elem) {
console.log('new window')
var mywindow = window.open('', 'PRINT', 'height=600,width=800');
// Add this function here
function printWindow(){
console.log('loaded my window');
mywindow.print();
}
// call it once the new window is loaded.
mywindow.document.onload = printWindow();
mywindow.document.write('<html><head>' + document.head.innerHTML + '</head><body>');
mywindow.document.write('<h1>' + document.title + '</h1>');
mywindow.document.write(document.getElementById(elem).innerHTML);
mywindow.document.write('</body></html>');
return true;
}
It may help..
I am trying to open a new window using window.open with dynamic content (for print functionality I am using this dynamic content).
Below dynamic HTML is not visible on window.open page where as in view source it is available. Please help me out why it is not getting displayed there.
Below is the code.
var win = window.open('', 'title', 'toolbar=0,location=0,menubar=0,resizable=yes,width=' + (screen.width - 100) + ', height=' + (screen.height - 150));
win.document.write("<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>");
win.document.write("<html>");
win.document.write("<head><title>title</title>");
win.document.write('<script language="javascript" type="text/javascript">function printPage() { PrintDiv("defaultPrintBuffer"); }<\/script>');
win.document.write('</head>');
win.document.write('<body>');
win.document.write("<iframe width='560' height='315' id='defaultPrintBuffer2' name='defaultPrintBuffer2'>");
win.document.write(iframeContent);
win.document.write("</iframe>");
win.document.write('</body>');
win.document.write("</html>");
win.document.close();
win.focus();
win.printPage();
Since you mention that you're trying to implement printing, I'll add how I solved this problem in an answer instead of a comment, so the code is more readable.
Basically I made an empty (but valid) html page and just insert nodes into that page before printing it. This avoids the use of document.write and iframes, which are considered bad practice in alot of cases. If you really want to use an iframe, just add the iframe to the print page html and append your content to that node instead of to the body.
var data = $('myPartOfPageSelector'),
printPage;
if (!data || !data.length) alert('Nothing to print.');
else {
printPage = window.open('resources/print.html');
setTimeout(function() {
printPage.document.body.innerHTML = data.innerHTML;
printPage.print();
printPage.close();
}, 100);
}
The iframe tag doesn't show the content that you put in it, you have to load a page in the iframe.
You could use a script to put content in the iframe:
win.document.write("<iframe width='560' height='315' id='defaultPrintBuffer2' name='defaultPrintBuffer2'>");
win.document.write("</iframe>");
win.document.write("<script type='text/javascript'>var doc = document.getElementById('defaultPrintBuffer2').contentWindow.document;doc.open();doc.write('" + iframeContent.replace("'","\\'").replace("\\","\\\\") + "');doc.close();</script>");
Note that the content should be a complete HTML document in itself.
<script>
var win = window.open();
win.document.body.innerHTML = "this is html that I want to print";
win.onload = function () { win.print(); }
</script>
everything works but print, how do I wait until the page loads the dynamic html with blank URL, then print?
I don't think there is a way to do it, like the user below me the onload wont fire probably because as soon as the window opened the page was already loaded. What I'm trying to do is load the entire page FIRST then print. The script I posted doesn't do this.
Martin, using your code:
<script>
var win = window.open();
win.document.body.innerHTML = "<img src='https://upload.wikimedia.org/wikipedia/commons/2/24/Willaerts_Adam_The_Embarkation_of_the_Elector_Palantine_Oil_Canvas-huge.jpg'/>";
win.print();
</script>
In chrome it prints a blank page.
EDIT:
Martin, the onload img attribute did the trick. Heres what I did to modify the script:
<script>
var win = window.open();
var html = "this is some test html <br><img src='https://upload.wikimedia.org/wikipedia/commons/2/24/Willaerts_Adam_The_Embarkation_of_the_Elector_Palantine_Oil_Canvas-huge.jpg'/>";
html = html.replace("<img ","<img onload='window.print();' ");
win.document.body.innerHTML = html;
</script>
So all img tags will add a onload=window.print. But really only one of them needs a onload (I'm pretty sure....). But to give you more information, in my scenario the variable html could be an infinite number of images, random text,tables, etc. It could be anything. Thank you Martin for having the patience to re-read this thread and reply.
Jeff, to make it work with an image, I'm pasting an example below. However, depending on exactly how your final page will look like perhaps a more generic solution is needed. Will your page be more complex?
<script>
var win = window.open();
win.document.body.innerHTML = "<img src='https://upload.wikimedia.org/wikipedia/commons/2/24/Willaerts_Adam_The_Embarkation_of_the_Elector_Palantine_Oil_Canvas-huge.jpg' onload='window.print();'/>";
</script>
This works (without images):
<script>
var win = window.open();
win.document.body.innerHTML = "this is html that I want to print";
win.print();
</script>
I don't think you need onload as you're not loading a page, so probably it won't fire.
My web page opens app.html first.After clicking to login i need to open index.html which i open in iframe and i dynamically create iframe in javascript.so to open that i frame im appending to document.body.But it appends to the body of the app.html.But I need to open in new page
var el = document.createElement("iframe");
el.setAttribute('id', 'ifrm');
el.setAttribute('name', 'ifrm');
el.setAttribute('src', '/index/index.html');
el.setAttribute('width', '100%');
el.setAttribute('height', '100%');
el.setAttribute('scrolling', 'no');
document.body.appendChild(el);
You could use this to open in a new window:
var myWindow = window.open("/index/index.html");
You would have to layer the iframe over the current page
el.style.position = 'absolute';
el.style.top = 0;
el.style.left = 0;
You question is a bit unclear as to what you are trying to do. The answer all depends on things like:
Are you trying to open index.html in addition to app.html or instead of it?
If you want both open, then do you want to open in a new window?
If so, do you want a regular window (i.e. same size as the original, without modification). Yes, then use JavaScript:
newWin = window.open("index.html", "My App's Main Window", winOptions);
or a specific size window, with other modifications (no Navigation bar, No address bar, etc) - in other words do you want a Popup Window
<html>
<head>
<title>JavaScript Popup Example</title>
<script type="text/javascript">
function loginCheck(){
//isLoggedIn is a boolean variable you've set to check login
if (isLoggedIn) {
popup();
}
}
function popon(){
var winOptions = "";
winOptions += "location=1, ";
winOptions += "status=0, ";
winOptions += "scrollbars=0, ";
winOptions += "width=100, ";
winOptions += "height=100";
newWin = window.open(
"index.html",
"My App's Main Window",
winOptions
);
newWin.moveTo(400, 300); //300 pixels down,
//400 pixels to the right
}
</script>
</head>
<body onload="javascript: loginCheck()">
<h1>JavaScript Popup Example</h1>
</body>
</html>
Or do you want to open index.html in a new tab?
simply use the target attribute in your anchor tag with the value set to new, e.g. <a target="new"...
If you are trying to replace index.html/open in the same tab... you don't need to do anything with your href
If you want to open the content of app.html WITHIN the app.html page somehow... then you either:
Need to use an iframe (that can already be tagged in the app.html (you don't need to create it dynamically with JavaScript) and load index.html into it OR...
Use AJAX to load the page behind the scenes while app.html is STILL loaded, in the window/tab... without reloading or replacing it. Once the AJAX request completes, youi would then do something with the HTML from index.html... like:
use plain vanilla JavaScript to dynamically create a div (or show a hidden div) and fill it once index.html is loaded.
use a (jQuery) widget such as a tab/tab set or accordion and fill it when app.html is loaded
I'm using window.open to create an empty window and then populating it using jquery DOM manipulation methods. One thing I'd like to do is make sure the new window has all the same scripts available in it that are in the parent window. I'm also duplicating all the style sheets, plus any other data that's in the parent window HEAD section, so what I decided to do is this:
$(floatingMap.window.document.head).append(
$("<base>", {"href": location.href})).append(
$("head").children().clone()));
This first creates a <base> tag that ensures the relative URLs in the source document are interpreted correctly, then injects a copy of all the tags from the head section of the source document. I can inspect the injected objects in the new window using Chrome's DOM inspector, and everything looks OK, but the problem I'm having is that the scripts aren't loading. The stylesheets, on the other hand, are loading fine. Any ideas what I can do to make the scripts load correctly?
Update:
In a potentially related problem, I've found that the following code has unexpected results:
$(floatingMap.window.document.head).append(
$("<script>").text("window.opener.childWindowReady()"));
This causes the specified code to execute in the context of the parent window, not the child window. Any ideas why this would be the case?
This appears to be a jquery bug. Excluding the script tags from the jquery operation and then adding those using pure javascript works as expected:
var scripts = document.getElementsByTagName("script");
function loadScript (index)
{
if (index == scripts.length)
onChildWindowReady ();
else if (scripts[index].src)
{
console.log ("injecting: " + scripts[index].src);
var inject = document.createElement("script");
inject.src = scripts[index].src;
floatingMap.window.document.head.appendChild(inject);
inject.onload = function () { loadScript (index + 1); };
}
else
loadScript (index + 1);
}
loadScript (0);
In addition with document.writeln it is possible to add all contents dynamically and also execute them.
For example,
jQuery(document).ready(function(){
jQuery('body').append("jquery loaded");
var w = window.open();
var htmlContent = document.documentElement;
w.document.writeln("<html>"+htmlContent.innerHTML+"</html>");
w.document.close();
});
This demostrates opening a clone of the jsfiddle result window that will include jquery as well as script content within head.
http://jsfiddle.net/6Qks8/