Scripting Support for Web Page Printing Sample

 

Please look at the code, and then check out the overview below:

if ( printIsNativeSupport() )
  window.print2 = window.print;
window.print = printFrame;

// main stuff
function printFrame(frame, onfinish) {
  if ( !frame ) frame = window;

  function execOnFinish() {
    switch ( typeof(onfinish) ) {
      case "string": execScript(onfinish); break;
      case "function": onfinish();
    }
    if ( focused && !focused.disabled ) focused.focus();
  }

  if ( frame.document.readyState !== "complete" &&
       !confirm("The document to print is not downloaded yet! Continue 
      with printing?") )
  {
    execOnFinish();
    return;
  }

 if ( window.print2 ) { // IE5
    var focused = document.activeElement; 
    frame.focus();
    if ( frame.print2 ) frame.print2();
    else frame.print();
    execOnFinish();
    return;
  }
 
  var eventScope = printGetEventScope(frame);
  var focused = document.activeElement;
 
  window.printHelper = function() {
    execScript("on error resume next: printWB.ExecWB 6, 1", "VBScript");
    printFireEvent(frame, eventScope, "onafterprint");
    printWB.outerHTML = "";
    execOnFinish();
    window.printHelper = null;
  }
 
  document.body.insertAdjacentHTML("beforeEnd",
    "<object id=\"printWB\" width=0 height=0 \
    classid=\"clsid:8856F961-340A-11D0-A96B-00C04FD705A2\">");
 
  printFireEvent(frame, eventScope, "onbeforeprint");
  frame.focus();
  window.printHelper = printHelper;
  setTimeout("window.printHelper()", 0);
}


// helpers
function printIsNativeSupport() {
  var agent = window.navigator.userAgent;
  var i = agent.indexOf("MSIE ")+5;
  return parseInt(agent.substr(i)) >= 5 && agent.indexOf("5.0b1") < 0;
}

function printFireEvent(frame, obj, name) {
  var handler = obj[name];
  switch ( typeof(handler) ) {
    case "string": frame.execScript(handler); break;
    case "function": handler();
  }
}

function printGetEventScope(frame) {
  var frameset = frame.document.all.tags("FRAMESET");
  if ( frameset.length ) return frameset[0];
  return frame.document.body;
}

Overview

Most of the code was developed to properly emulate IE5's sparkling new examples of elegance and brevity—the print() method and the onbeforeprint/onafterprint events—for Internet Explorer 4.x. Thankfully you can now just include print.js as a pre-built 'module' and make the same calls for Internet Explorer 4.x or Internet Explorer 5.

If, however, you'd like to know more about some of the advanced DHTML/JScript techniques we used to get this to work, then read on.

One subtle thing about the JScript language is that a JScript function is actually an object. This is true for a nested function, too, and is extremely useful for callbacks (e.g., our printHelper) as it means that from the nested function we can still reference any local variable owned by its parent function, regardless of the fact that the flow control has already gone out of the scope of the parent! This is how—at the time of printHelper (nested into printFrame)—we can reference the frame, onfinish, focused variables that are local to printFrame, even though printFrame has already returned.

An interesting helper is function printFireEvent(frame, obj, name). It's used to "fire" onbeforeprint/onafterprint events for Internet Explorer 4.x (that doesn't natively support them). Here is a snippet illustrating this for the <BODY> tag:

<body onbeforeprint="beforeprint()" onafterprint="afterprint()">
...
<script>
function beforeprint() { ... }
function afterprint() { ... }
</script>
</body>
// this could suit, too
document.body.onbeforeprint = function() { ... } 
// time to call
printFireEvent(window, document.body, "onbeforeprint")
...
printFireEvent(window, document.body, "onafterprint")

This features the power of JScript's object capabilities, and the custom attribution of DHTML tags.

The following code is used to print a hidden page of content:

function printHidden(url) {
  document.body.insertAdjacentHTML("beforeEnd",
    "<iframe name=printHiddenFrame width=0 height=0></iframe>");
  var doc = printHiddenFrame.document;
  doc.open();
  doc.write("<body onload=\"parent.onprintHiddenFrame()\">");
  doc.write("<iframe name=printMe width=0 height=0 src=\"" + 
      url + "\"></iframe>");
  doc.write("</body>");
  doc.close();
}

function onprintHiddenFrame() {
  function onfinish() {
    printHiddenFrame.outerHTML = "";
    if ( window.onprintcomplete ) window.onprintcomplete();
  }
  printFrame(printHiddenFrame.printMe, onfinish);
}

To do this, we create a hidden inline frame (say, 'A') in much the same way as WebBrowser—with insertAdjacentHTM—then generate another inline frame 'B' inside 'A' and navigate 'B' to our required URL. Lastly, we need 'B' to handle the download complete event upon which we do printing. In your calling code you may assign window.onprintcomplete to be notified when a document gets downloaded and sent to the print queue.

Conclusion

We apologize for anything that's still not clear—or that makes you go "AAAGGGHHH!!!—and we'll be glad to answer any of your in-depth questions. Write us!