It's long been a hassle to easily generate printable content from within Web pages, and this is a source of serious aggravation for Web application developers (all developers, not just ColdFusion developers). Considering that a very significant chunk of Web application development tends to be data reporting and presentation type applications, this is a big problem. The truth is, Web browsers just don't print Web pages properly, so developers have had to resort to complex and painful work-arounds to put content in a printable format. ColdFusion solves this problem simply with the <cfdocument> family of tags. Using the <cfdocument> TagWe'll start with a really simple example. Listing 16.8 contains simple text wrapped within a pair of <cfdocument> tags. The generated output is seen in Figure 16.8. Listing 16.8. Print1.cfmBasic PDF Generation<!--- Name: Print1.cfm Author: Ben Forta Description: Simple printable output Created: 01/10/05 ---> <cfdocument format="pdf"> Hello world! </cfdocument> Figure 16.8. Adobe PDF format is the most commonly used printable document format on the Web.The code in Listing 16.8 couldn't be simpler. By wrapping text in between <cfdocument> and </cfdocument> tags, content between those tags is converted into a PDF file on the fly, and embedded in the page. In addition to PDF, ColdFusion can generate FlashPaper, a lightweight alternative to PDF, and one that only requires that the Flash Player be present on the browser. To generate FlashPaper, simply change format="pdf" to format="flashpaper" to generate a page like the one seen in Figure 16.9. Figure 16.9. FlashPaper is a lightweight alternative to PDF that requires only the Flash Player on the client.Of course, you're not limited to static text; you can use dynamic CFML within the document content, too. Listing 16.9 uses a mixture of HTML, CFML, and dynamic data to create a printable report (seen in Figure 16.10). Listing 16.9. Print2.cfmData-Driven Document Generation<!--- Name: Print2.cfm Author: Ben Forta Description: Data driven printable output Created: 01/10/05 ---> <!--- Get budget data ---> <cfinvoke component="ChartData" method="GetBudgetData" returnvariable="BudgetData"> <!--- Generate document ---> <cfdocument format="pdf"> <!--- Header ---> <table align="center"> <tr> <td> <img src="/books/2/448/1/html/2/../images/logo_c.gif" alt="Orange Whip Studios"> </td> <td align="center"> <font size="+2">Orange Whip Studios<br>Movies</font> </td> </tr> </table> <!--- Title ---> <div align="center"> <h2>Budget Data</h2> </div> <!--- Details ---> <table> <tr> <th>Movie</th> <th>Budget</th> </tr> <cfoutput query="BudgetData"> <tr> <td><strong>#MovieTitle#</strong></td> <td>#LSCurrencyFormat(AmountBudgeted)#</td> </tr> </cfoutput> </table> </cfdocument> Figure 16.10. Printable output may contain HTML, CFML, and more.What Is Supported by <cfdocument>?You'll notice that the code in Listing 16.9 uses a mixture of HTML (including tags like <font>, which generally should be avoided), an image, tables, CFML expressions, and more. The <cfdocument> tag supports all of the following:
In other words, <cfdocument> should be more than able to convert all sorts of pages into printable PDF or FlashPaper. Creating Printable Versions Of PagesYou will likely often need to create printable versions of existing pages. It would be tempting to try and simply conditionally include <cfdocument> tags in existing pages, but unfortunately that won't work: ColdFusion won't parse the page correctly because it thinks your tags aren't properly paired. The solution to this problem is to create a wrapper page, one that defines the printable document and includes the original page. Listing 16.10 is a modified version of a page we created back in Chapter 11, it simply displays movie details. The modified page is seen in Figure 16.11. Listing 16.10. details.cfmMovie Details Page<!--- Name: details.cfm Author: Ben Forta (ben@forta.com) Description: CFC driven data drill-down details with complete validation Created: 12/15/04 ---> <!--- Movie list page ---> <cfset list_page="movies.cfm"> <!--- Make sure FilmID was passed ---> <cfif not IsDefined("URL.filmid")> <!--- it wasn't, send to movie list ---> <cflocation url="#list_page#"> </cfif> <!--- Get movie details ---> <cfinvoke component="ows.11.movies" method="GetDetails" returnvariable="movie" Film> <!--- Make sure have a movie ---> <cfif movie.RecordCount IS 0> <!--- It wasn't, send to movie list ---> <cflocation url="#list_page#"> </cfif> <!--- Build image paths ---> <cfset image_src="/books/2/448/1/html/2/../images/f#movie.FilmID#.gif"> <cfset image_path=ExpandPath(image_src)> <!--- Create HTML page ---> <html> <head> <title>Orange Whip Studios - Movie Details</title> </head> <body> <!--- Display movie details ---> <cfoutput query="movie"> <table> <tr> <td colspan="2"> <!--- Check of image file exists ---> <cfif FileExists(image_path)> <!--- If it does, display it ---> <img src="/books/2/448/1/html/2/../images/f#filmid#.gif" alt="#movietitle#" align="middle"> </cfif> <b>#MovieTitle#</b> </td> </tr> <tr valign="top"> <th align="right">Tag line:</th> <td>#PitchText#</td> </tr> <tr valign="top"> <th align="right">Summary:</th> <td>#Summary#</td> </tr> <tr valign="top"> <th align="right">Released:</th> <td>#DateFormat(DateInTheaters)#</td> </tr> <tr valign="top"> <th align="right">Budget:</th> <td>#DollarFormat(AmountBudgeted)#</td> </tr> </table> <p> <!--- Links ---> [<a href="detailsprint.cfm?FilmID=#URL.FilmID#">Printable page</a>] [<a href="#list_page#">Movie list</a>] </cfoutput> </body> </html> Figure 16.11. It's often convenient to provide links to printable versions of pages.The big change to this page is a line added to the links section at the bottom. A new link to a Printable page has been created; when clicked, it opens detailsprint.cfm passing the FilmID to that page. The code for that page is remarkably simple, as seen in Listing 16.11. Listing 16.11. detailsprint.cfmPrintable Movie Details Page<!--- Name: detailsprint.cfm Author: Ben Forta (ben@forta.com) Description: Printable version of details pahge Created: 12/15/04 ---> <cfdocument format="pdf"> <cfinclude template="details.cfm"> </cfdocument> Listing 16.11 creates a document using <cfdocument> tags, and includes the existing details page to generate the printable output seen in Figure 16.12. Figure 16.12. Include an existing page to make it printable.NOTE The links in details.cfm work in the generated printable output. In addition to the format attribute used here, <cfdocument> supports a whole series of attributes to give you greater control over printed output. Table 16.9 lists the supported attributes.
Saving Generated Output<cfdocument> embeds generated output in your Web page. You may opt to save the generated files to disk instead of serving them in real time. Reasons to do this include:
To save generated output, simply provide a filename in the filename attribute. Controlling Output using The <cfdocumentitem> Tag<cfdocumentitem> is used within a <cfdocument> tag set to embed additional items. <cfdocumentitem> requires that a type be specified. Table 16.10 lists the supported types.
NOTE Page breaks are calculated automatically by ColdFusion. Use <cfdocumentitem type="pagebreak"> to embed manual breaks. Listing 16.12 is a revised printable movie listing, the output of which is seen in Figure 16.13. Listing 16.12. Print3.cfmPrintable Output with Additional Items<!--- Name: Print3.cfm Author: Ben Forta Description: Printable output with additional options Created: 01/10/05 ---> <!--- Get budget data ---> <cfinvoke component="ChartData" method="GetBudgetData" returnvariable="BudgetData"> <!--- Generate document ---> <cfdocument format="pdf"> <!--- Header ---> <cfdocumentitem type="header"> OWS Budget Report </cfdocumentitem> <!--- Footer ---> <cfdocumentitem type="footer"> <p align="center"> <cfoutput> #CFDOCUMENT.currentpagenumber# of #CFDOCUMENT.totalpagecount# </cfoutput> </p> </cfdocumentitem> <!--- Header ---> <table align="center"> <tr> <td><img src="/books/2/448/1/html/2/../images/logo_c.gif" alt="Orange Whip Studios"></td> <td align="center"><font size="+2">Orange Whip Studios<br>Movies</font></td> </tr> </table> <!--- Title ---> <div align="center"> <h2>Budget Data</h2> </div> <!--- Page break ---> <cfdocumentitem type="pagebreak" /> <!--- Details ---> <table> <tr> <th>Movie</th> <th>Budget</th> </tr> <cfoutput query="BudgetData"> <tr> <td><strong>#MovieTitle#</strong></td> <td>#LSCurrencyFormat(AmountBudgeted)#</td> </tr> </cfoutput> </table> </cfdocument> Figure 16.13. Generated documents may contain page headers and footers.Listing 16.12 warrants some explanation. The <cfdocument> content now contains the following code: <!--- Header ---> <cfdocumentitem type="header"> OWS Budget Report </cfdocumentitem> This code defines a page header, text that will be placed at the top of each page. A footer is also defined as follows: <!--- Footer ---> <cfdocumentitem type="footer"> <p align="center"> <cfoutput> #CFDOCUMENT.currentpagenumber# of #CFDOCUMENT.totalpagecount# </cfoutput> </p> </cfdocumentitem> This page footer contains two special variables. Within a <cfdocument> tag, a special scope exists named CFDOCUMENT. It contains two variables, as listed in Table 16.11. These variables may be used in headers and footers, as used in this example.
In addition, the code in Listing 16.12 embeds a manual page break using this code: <!--- Page break ---> <cfdocumentitem type="pagebreak" /> <cfdocumentitem> must always have an end tag, even when no body is used. The trailing / is a shortcut that you can use. In other words, the above tag is functionally identical to: <!--- Page break ---> <cfdocumentitem type="pagebreak"></cfdocumentitem> Defining Sections with <cfdocumentsection>As you have seen, you have a lot of control over generated pages using the <cfdocument> and <cfdocumentitem> tags. But sometimes you may want different options in different parts of the same document. For example, you may want a title page to have different margins than other pages. Or you may want different headers and footers in different parts of the document. To do this, you use <cfdocumentsection> tags. A <cfdocument> tag pair may contain one or more sections, each defined using <cfdocumentsection> tags. Within each section you can specify alternate margins, and can use <cfdocumentitem> tags to specify headers and footers for each section. NOTE When using <cfdocumentsection>, all content must be in sections. ColdFusion ignores any content outside of sections. |