15

I have a documentation type page with an iframe inside. I'm trying to override standard browser print (Ctrl + p) to print contents of an iframe only.

I know how to print an iframe content using javascript:

window.frames['webcontent'].focus();
window.frames['webcontent'].print();

I know how to do run javascript before printing e.g. as described here: Check for when a user has selected to print using javascript

Any advise?

Thanks

Community
  • 1
  • 1
Burjua
  • 12,506
  • 27
  • 80
  • 111

6 Answers6

22

It can be easily achieved through CSS: See thisJSfiddle: Tested

<style>
@media print{
    body * {display:none;}
    .toPrint{display:block; border:0; width:100%; min-height:500px}
}
</style>

Let an HTML File be:

<body>
    <h3>I do not want this title Printed</h3>
    <p> This paragraph should not be printed</p>
    <iframe class="toPrint" src="http://akitech.org"></iframe>
    <button onclick="window.print()">Print</button>
</body>
tika
  • 7,135
  • 3
  • 51
  • 82
  • 1
    Using `body * {} ` selects all body elements in CSS – tika Jul 28 '14 at 17:06
  • That's the point. It hides all body elements when the print dialog is rendering the page so as to only display the iframe (due to the second css rule). It won't apply to the iframe's body because the frame's parent window's css has no bearing over it. – Slight Jul 15 '15 at 20:55
  • This prints an iframe with scrollbars cropping content in both chrome and IE for me. – cchamberlain Oct 31 '16 at 03:58
6

It's not possible (using Javascript). There is some experimental support for user-initiated print events in modern browsers, but those are not cancelable ("simple events") so the entire page will still print even if you interject custom code to print the frame of interest.

Given this limitation, your best bet is probably to offer users a large button that fires your custom frame printing function (see printContentFrameOnly below, fire it without arguments) and hope that they'll use the button instead of ctrl-p.

If it would be possible, this would be the way to do it (based on this answer):

// listener is a function, optionally accepting an event and
// a function that prints the entire page
addPrintEventListener = function (listener) {

    // IE 5.5+ support and HTML5 standard
    if ("onbeforeprint" in window) {
        window.addEventListener('beforeprint', listener);
    }

    // Chrome 9+, Firefox 6+, IE 10+, Opera 12.1+, Safari 5.1+
    else if (window.matchMedia) {
        var mqList = window.matchMedia("print");

        mqList.addListener(function (mql) {
            if (mql.matches) listener();  // no standard event anyway
        }); 
    }

    // Your fallback method, only working for JS initiated printing
    // (but the easiest case because there is no need to cancel)
    else {    
        (function (oldPrint) { 
            window.print = function () {
                listener(undefined, oldPrint);
            }
        })(window.print);
    }
}

printContentFrameOnly = function (event) {
    if (event) event.preventDefault();  // not going to work
    window.frames['webcontent'].focus();
    window.frames['webcontent'].print();
}

addPrintEventListener(printContentFrameOnly);
Community
  • 1
  • 1
Julian
  • 4,176
  • 19
  • 40
  • I was looking for a javascript solution, as css didn't work for me. Marking this as an answer. – Burjua Aug 05 '14 at 12:42
  • Thank you. For what it's worth, I completely agree xDNP deserved the bounty award, and I also upvoted their answer. – Julian Aug 05 '14 at 18:21
4

The idea is to set the iframe content somewhere on the page, and print ONLY that content, by hiding the original content.

This can be done by getting the iframe content when Ctrl+P event is being initiated (via JavaScript), and print only its content (via CSS @media type).

HTML Code:

    <div id="dummy_content"><!-- Here goes the iframe content, which will be printed --></div>
    <div id="content_wrapper">
        <div id="current_content">Current Content that the user see<div>
        <iframe id="myIframe" src="iframe.html"></iframe>
    </div>

CSS Code:

@media screen {
    #dummy_content {
        display:none; /* hide dummy content when not printing */
    }
}            
@media print {
    #dummy_content {
        display:block; /* show dummy content when printing */
    }
    #content_wrapper {
        display:none; /* hide original content when printing */
    }
}

JavaScript Code:

        var dummyContent = document.getElementById("dummy_content");
        function beforePrint() {
              var iFrame = document.getElementById("myIframe");
              dummyContent.innerHTML = iFrame.contentWindow.document.body.innerHTML; // populate the dummy content (printable) with the iframe content
        }

        document.onkeydown = function(e) {
            if (e.ctrlKey && e.keyCode == 80) {
                beforePrint();
            }
        }
Yonatan Ayalon
  • 1,959
  • 18
  • 19
1

You can define a css file for printing:

  @media print {
    * { display: none; }
   iframe { display: block; }
  }

EDIT

Mybad didnt tested it.

* { display: none; } is somehow overwriting all

But this is working like a charm

http://jsfiddle.net/c4e3H/

  @media print {
    h1, p{ display: none; }   
  }
jungerislaender
  • 304
  • 1
  • 12
  • Nope, it doesn't work, just prints an empty page. Chrome doesn't print iframe content even without this rule, so I don't think I can do it with css only. – Burjua Jul 25 '14 at 12:29
  • Your first one doesn't work because `* { display: none; }` hides parent elements of your `iframe` (`html` / `body`). – cchamberlain Oct 31 '16 at 03:06
0

The only way i can think of is hiding all the content in the document except for the iframe and making it fit the whole document.

<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<style type="text/css">
body.hide *, body #backdrop
{
    display: none !important;
}   
body.hide #my_print_iframe, body.hide #backdrop
{
    background: white;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    border: 0;
    width: 100%;
    height: 100%;
    display: block !important;
}
@media print {
    body.hide #backdrop
    {
        display: none !important;
    }
}
</style>
  <script>
    $(document).on('keydown', function(e){
        if (e.keyCode == 80 && ( e.metaKey || e.ctrlKey ) ) {
            $("body").addClass('hide');
            setTimeout(function(){
                $("body").removeClass('hide');
            },1000)
       }
    })
  </script>
</head>
<body>
  <div>
    this is some visible text
  </div>
  <iframe id="my_print_iframe" src="//example.com"></iframe>
</body>
</html>

I used timeout ( nasty i know ) because at least chrome 38 does not send the keyup event after ctrl+p

Alexandru Eftimie
  • 149
  • 1
  • 1
  • 11
0

Hi might be this code will help you..

function PrintElem(elem)
{
     Popup($(elem).html());
}

function Popup(data)
{
     var mywindow = window.open('', 'printMe', 'height=400,width=600');
     mywindow.document.write('<html><head><title>Print Me</title>');
     mywindow.document.write('</head><body >');
     mywindow.document.write(data);
     mywindow.document.write('</body></html>');

     mywindow.print();
     mywindow.close();

     return true;
}

and call the function PrintElem('iframe') on you page.

user2706194
  • 199
  • 8