惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
Help Net Security
Help Net Security
P
Privacy International News Feed
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
AWS News Blog
AWS News Blog
K
Kaspersky official blog
A
Arctic Wolf
Latest news
Latest news
T
Threat Research - Cisco Blogs
L
LINUX DO - 最新话题
P
Privacy & Cybersecurity Law Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Google DeepMind News
Google DeepMind News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
月光博客
月光博客
N
News and Events Feed by Topic
Jina AI
Jina AI
博客园 - 司徒正美
WordPress大学
WordPress大学
罗磊的独立博客
雷峰网
雷峰网
AI
AI
Hugging Face - Blog
Hugging Face - Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Security @ Cisco Blogs
博客园 - 三生石上(FineUI控件)
H
Heimdal Security Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Cisco Blogs
博客园 - 【当耐特】
The Hacker News
The Hacker News
有赞技术团队
有赞技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Schneier on Security
Schneier on Security
博客园 - Franky
S
SegmentFault 最新的问题
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Cloudbric
Cloudbric
爱范儿
爱范儿
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Secure Thoughts
Last Week in AI
Last Week in AI
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Know Your Adversary
Know Your Adversary
Google DeepMind News
Google DeepMind News

博客园 - 永红

东莞依时利诚聘java与.net方面的英才 项目管理笔记(观念) 项目管理笔记(概述) 【置顶】DLPrinter WEB打印组件第2次更新 也谈WEB打印(五):在IE的打印预览窗口中定义自己的用户接口 也谈WEB打印(三):抛开IE,实现我们自己的打印模板 也谈WEB打印(二):简单的分析一下IE的打印原理并实现简单的打印和预览 也谈WEB打印(-):目前的几种方式及我们的任务 整理的几个常用的数据库维护的脚本 揭秘SQL Server 2000中的Bookmark Lookup 用MSIL剥开C#的外衣(一):方法参数ref、out、params和lock、for和foreach关键字 【翻译】MSIL 教程(三):类和异常处理 【翻译】MSIL 教程(二):数组、分支、循环、使用不安全代码和如何调用Win32 API 【翻译】MSIL 教程(一) 设计模式实战:用Prototype模式提高系统的开发效率,用DynamicMethod、Flyweight模式提高系统的运行效率 用DynamicMethod提升ORM系统转换业务数据的性能 设计模式实战:在WinForm中用Command模式实现可以撤销的数据操作 把Sql数据转换为业务数据的几种方法 设计模式实战:组合型模式Composite,Adapter
也谈WEB打印(四):让我们的模板支持打印,并根据内容动态的生成页面
永红 · 2007-10-15 · via 博客园 - 永红
   

在上一篇文章也谈WEB打印(三):抛开IE,实现我们自己的打印模板中,我们写了一个自己的打印模板,然而,该模板并不支持打印,也只能显示2个页面。在本文,我们继续完善该模板,以让他支持打印,并且可以根据被打印的内容动态的生成页面。

   废话少说,我们先来分析这个模板:
<!-- Template2.htm: 一个很小的模板,它支持打印
这个模板展示了一个最小的打印模板,他可以打印我们在预览时见到的内容。本模板与Template1.htm完全相同,只是增加了TEMPLATEPRINTER元素和一些支持打印的脚本。这些脚本以函数CheckPrint开始。该函数处理第二个LAYOUTRECT元素的onlayoutcomplete事件,由一个时间是100毫秒的定时器触发。CheckPrint检查dialogArguments.__IE_PrintType 属性来决定是否是预览文档,或者是在打印之前需要以一个打印对话框来提示用户,还是不提示用户而直接打印。使用定时器来延时非常重要,因为设备上下文(DC)在onlayoutcomplete时间没有完成之前,不能渲染打印机或者屏幕。延时让使得打印发生在onlayoutcomplete事件完成后再开始。1毫秒就足够让onlayoutcomplete时间完成,但为了安全起见,在本例中,把定时器设为100毫秒。
PrintPrep是一个重要的函数,因为设置了一个onreadystatechange处理函数,以确定模板的源文档在打印之前被完全装入。
-->

<HTML XMLNS:IE>
<HEAD>
<?IMPORT NAMESPACE="IE" IMPLEMENTATION="#default">
<STYLE TYPE="text/css">
.lorstyle
{
    width:5.5in;
    height:8in;
    margin:1in;
    background:white;   
    border:1 dashed gray;
}
.pagestyle

    width:8.5in;
    height:11in;
    background:#FFFF99;   
    border-left:1 solid black;
    border-top:1 solid black;
    border-right:4 solid black;
    border-bottom:4 solid black;
    margin:10px;
}
</STYLE>
<SCRIPT LANGUAGE="JScript">
function CheckPrint()
{
     switch (dialogArguments.__IE_PrintType)
     {
         case "Prompt":
              if (printer.showPrintDialog()) 
                   PrintPrep();
              break;
         case "NoPrompt":
              PrintPrep();
              break;
         case "Preview":
         default:
              break;
     }
}

function PrintPrep()
{
     if (layoutrect1.contentDocument.readyState == "complete")
     {
         //这一块会被调用当提示用户后再打印的时候,因为打印对话框会给出时间,
         //让文档内容被完全装入。
         PrintNow();
     }
     else
     {
         // This block will usually be called when printing w/o user prompt
         // and sets an event handler that listens for the loading of the content
         // document before printing. Sometimes, however, the content document
         // will be loaded in time for the previous block to execute      
         layoutrect1.contentDocument.onreadystatechange = PrintWhenContentDocComplete;
     }
}

function PrintWhenContentDocComplete()
{
     if (layoutrect1.contentDocument.readyState == "complete")
     {
         layoutrect1.contentDocument.onreadystatechange = null;
         PrintNow();
     }
}

function PrintNow()
{
     printer.startDoc("Printing from Tmplt2.htm");
     printer.printPage(page1);   
     printer.printPage(page2);
     printer.stopDoc();
}
</SCRIPT>

<IE:TEMPLATEPRINTER ID="printer"/>
</HEAD>

<
BODY>
<IE:DEVICERECT ID="page1" CLASS="pagestyle" MEDIA="print">
     <IE:LAYOUTRECT ID="layoutrect1" CONTENTSRC="document" CLASS="lorstyle" NEXTRECT="layoutrect2"/>
</IE:DEVICERECT>
<IE:DEVICERECT ID="page2" CLASS="pagestyle" MEDIA="print">
     <IE:LAYOUTRECT ID="layoutrect2" CLASS="lorstyle" ONLAYOUTCOMPLETE="setTimeout('CheckPrint()', 100)"/>
</IE:DEVICERECT>
</BODY>
</HTML>

启动我们在《也谈WEB打印(二):简单的分析一下IE的打印原理并实现简单的打印和预览》中的程序,在Template Address中输入文档模板的路径,然后在 Document Address中输入www.cnblgos.com,然后单击Print,你看到了什么?我这里的效果如下:

    终于出现我们想要的打印框,按下打印,也还真的打印出来了。呵呵,心里非常高兴。那么奥妙在哪里呢?其实大家看了模板中的注释,已经比较清楚了,我再解释一下。
   我们先来看CheckPrint函数,其代码如下:
function CheckPrint()
{
     switch (dialogArguments.__IE_PrintType)
     {
         case "Prompt":
              if (printer.showPrintDialog()) 
                   PrintPrep();
              break;
         case "NoPrompt":
              PrintPrep();
              break;
         case "Preview":
         default:
              break;
     }
}

大家可能都注意到了,该函数就是检查一个叫做dialogArguments对象的__IE_PrintType属性,然后调用相应的函数或者什么都不做,当__IE_PrintType的值为"Prompt""NoPrompt"的时候,就调用PrintPrep函数,而该函数就是进行打印。所以,关键就在dialogArguments对象,弄清楚了他,一切都明白了。

IE下进行JS开发的人应该都知道,window对象也有一个属性叫做dialogArguments。他们会不会有什么关系呢?根据MSDN上说法,他们其实就是一回事,不过这个dialogArguments有一些局限,只能应用于打印模板。dialogArguments 不管是否向用户显示预览,他都是可用的,其中最重要的一个属性就是__IE_PrintType,他说明了打印模板是否应该向用户进行提示。

除了dialogArguments对象外,我们还接触到了一个很重要的事件,那就是ONLAYOUTCOMPLETE,他在打印或者预览版面在用源文档的内容完成了填充当前版面(layout)的时候触发,该事件还有一个至关重要的属性,那就是contentOverflow,如果为true,那么就表示文档还没有显示完,否则就是文档显示玩了,所以,我们只要在处理ONLAYOUTCOMPLETE事件的时候,根据contentOverflow的值进行判断,就知道需要多少个页面。

上面的例子尽管可以打印了,但还是不能根据文档内容生成适当的页面,下面的例子,我们就来一个可以根据文档内容动态获取页面数量的模板。

<!-- Template3.htm: 动态生成LayoutRect (仅可预览)
   本模板演示了如何在源文档动态的装入模板的时候动态的生成LAYOUTRECT元素。第一个LAYOUTRECT在BODY元素的onload事件处理程序AddFirstPage中生成,其余的LAYOUTRECT在每个LAYOUTRECT的onlayoutcomplete事件处理函数——OnRectComplete——中生成。OnRectComplete检查event.contentOverflow属性,如果contentOverflow为true,函数为一个新的DEVICERECT和LAYOUTRECT元素生成HTML。一旦HTML被生成,OnRectComplete就会使用insertAjacentHTML方法把新的HTML插入到pageContainer这个DIV中。在新的LAYOUTRECT被插入后,模板可以继续装载模板的源文档。注意OnRectComplete也把当前LAYOUTRECT的onlayoutcomplete事件处理句柄设为null.这样就阻止了文档在重新装入的时候——例如窗口的大小被更改的时候——调用OnRectComplete。
   本模板仅支持打印预览。
-->
<HTML XMLNS:IE>
<HEAD>
<?IMPORT NAMESPACE="IE" IMPLEMENTATION="#default">
<STYLE TYPE="text/css">
.lorstyle
{
    width:5.5in;
    height:8in;
    margin:1in;
    background:white;   
    border:1 dashed gray;
}
.pagestyle

    background:#FFFF99;
    border-left:1 solid black;
    border-top:1 solid black;
    border-right:4 solid black;
    border-bottom:4 solid black;
    width:8.5in;
    height:11in;
    margin:10px;
    overflow:hidden;
}
</STYLE>

<SCRIPT LANGUAGE="JScript">
var iNextPageToCreate = 1;
function AddFirstPage()
{
    newHTML = "<IE:DEVICERECT ID='page1' MEDIA='print' CLASS='pagestyle'>";
    newHTML += "<IE:LAYOUTRECT ID='layoutrect1' CONTENTSRC='document' ONLAYOUTCOMPLETE='OnRectComplete()' EXTRECT='layoutrect2' CLASS='lorstyle'/>";
    newHTML += "</IE:DEVICERECT>";
    pagecontainer.insertAdjacentHTML("afterBegin", newHTML);
    iNextPageToCreate = 2;
}

function OnRectComplete()
{
    if (event.contentOverflow == true)
    {
        document.all("layoutrect" + (iNextPageToCreate - 1)).onlayoutcomplete = null;
        newHTML = "<IE:DEVICERECT ID='page" + iNextPageToCreate + "' MEDIA='print' CLASS='pagestyle'>";
        newHTML += "<IE:LAYOUTRECT ID='layoutrect" + iNextPageToCreate + "' ONLAYOUTCOMPLETE='OnRectComplete()' EXTRECT='layoutrect" + (iNextPageToCreate + 1) + "' CLASS='lorstyle'/>";
        newHTML += "</IE:DEVICERECT>";
        pagecontainer.insertAdjacentHTML("beforeEnd", newHTML);
        iNextPageToCreate++;
    }
}

</SCRIPT>

</HEAD>

<BODY ONLOAD="AddFirstPage()">
    <DIV ID="pagecontainer">
       <!--在这里动态的生成页面。 -->
    </DIV>
</BODY>
</HTML>

Document Address里输入保存有上述代码的htm文档的名字,然后单击Preview,效果如下图:

 
    博客园的首页在打印模板中的页数是
16页(这个数子当然不正确)。
    我们的打印模板现在可以根据被打印内容动态的生成页面了,可是还是有许多的内容没有完成,比如设置正确的纸张大小,设置页边距,设置页眉和页脚等。在下一篇文章,我们继续讨论这些内容。
    另外,老是用博客园的首页作为例子,不知DUDU有没有意见,如果有的话,就跟我说一声啊(^_^)。
    欢迎大家拍砖。