javascriptipadiframeprintingsafari

How to print the contents of an iFrame using Javascript on iPad?


Printing the contents of an iFrame already seemed a challenging problem to solve cross-browser. After testing a lot of approaches (some of which also found on this site), my current approach seems to work quite good cross-browser and looks like this:

function printUrl( elem, url ) {
    $( '#' + elem ).append( "<iframe style='border: none; width: 0; height: 0; margin: 0; padding: 0;' src='" + url + "' id='printFrame'></iframe>" );

    $( '#printFrame' ).load( function() {
        var w = ( this.contentWindow || this.contentDocument.defaultView );
        w.focus();
        w.print();
    } );
}

There is only a slight problem with this code when using an iPad. The iPad prints the page which contains the iFrame, instead of the contents of the iFrame. Safari on Mac correctly prints the contents of the iFrame, though.

Has anyone already solved this problem and been able to print the contents of an iFrame on an iPad?


Solution

  • Okay, first of all. I did not solve the problem. I created a work-around that actually fakes what I want to achieve.

    Because the iPad / iPhone simple prints the parent page, I wrap the complete body in a new div, then append the iFrame and some stylesheets which make sure that the printed document only contains the iFrame:

    function printUrl( url ) {
        $newBody = "<div class='do_not_print_this'>"
                    + $( 'body' ).html()
                    + "</div>"
                    + "<iframe style='border: none; 0; width: 100%; margin: 0; padding: 0;' src='" + url + "' class='printFrame'></iframe>"
                    + "<style type='text/css' media='all'>.printFrame { position: absolute; top: -9999999px; left: -99999999px; }</style>"
                    + "<style type='text/css' media='print'>.do_not_print_this { display: none; } .printFrame { top: 0; left: 0; }</style>";
        $( 'body' ).html( $newBody );
    
        $( '.printFrame' ).load( function() {
            var w = ( this.contentWindow || this.contentDocument.defaultView );
            w.focus();
            w.print();
        } );
    }
    

    Hiding the iframe for the browser in the normal view is done using absolute positioning, using display on none or visibility hidden introduced weird behavior in the final print.

    Yes, it's ugly. However, this is currently the only option I can think of which works. If any of you come up with a better solution, please let me know.