Site Tree

Adding Print and PDF functionality

Often it is very useful to add functionality to a site that allows a user to print a whole section to screen (which can then be printed to a printer) or to a PDF.

It is fairly straight-forward to create this in ShadoCMS. Here is how.

 

Create a Print Component

First, create a new ColdFusion component and save it as /yoursite/app_templates/coreobjects/print.cfc. Populate it with the following code. The code contains some comments that give some idea of what is the code doing.

<cfcomponent hint="A bunch of functions relating to printing sections of ShadoCMS sites">

<cffunction name="init" access="public" output="false" returnType="any" hint="I return an instance of myself">
<cfreturn this>
</cffunction>

<cffunction name="outputSection" access="public" returntype="void" hint="Prints a Section of a tree" output="yes">
<cfargument name="circuit_uuid" type="string"required="yes" hint="Circuit UUID of the section to print">
<cfargument name="containerPositions" type="string" required="true" hint="A comma-separated list of container positions to include in the output. Basically this is a list of the 'page_position' values that is passed to the addContainer2Page function.">
<cfargument name="rootsection" default="true"required="false" hint="Whether to include the root section in the output or not">
<cfargument name="parent" type="string"required="false"default=""hint="No need to pass in anything. This is used while the function recurses.">

<cfset var qCircuits = queryNew("")>
<cfset var qCircuitPages = queryNew("")>
<cfset var sParents= "">
<cfset var oSections = application.shado_obj_factory.get("shadomx.core.sections.shado_obj_sections")>
<cfset var oContainers = application.shado_obj_factory.get("shadomx.core.containers.shado_obj_containers")>
<cfset var iPos = 0>

<!--- If we doing the first run (root section) the output here. --->
<cfif arguments.rootsection is true>

<cfset qRootCircuitPages = oSections.getSectionPages(circuit_uuid="#arguments.circuit_uuid#", exstring="$")>

<cfloop query="qRootCircuitPages">

<h1>#qRootCircuitPages.page_title#</h1>

<cfloop list="#arguments.containerPositions#" index="iPos">
<cfset oContainers.addcontainer2page(page_position=iPos, page_uuid="#qRootCircuitPages.uuid#")>
</cfloop>
</cfloop>

</cfif>

<!--- now get the sub sections --->
<cfset qCircuits = oSections.getSubSections(parent_circuit_uuid="#arguments.circuit_uuid#", exstring="$")>

<cfoutput query="qCircuits">

<h1> #qCircuits.circuit_title#</h1>

<cfset qCircuitPages = oSections.getsectionpages(section_uuid="#uuid#", exstring="$")>

<cfloop query="qCircuitPages">

<!--- <cfset request.GETPAGEOBJECT.PAGE_UUID = uuid> --->

<!--- <a name="#replace('#arguments.parent#.#qCircuits.currentrow#.#qCircuitPages.currentrow#',' ','','all')#">
<cfif len(trim(arguments.parent))>#arguments.parent#.</cfif>#qCircuits.currentrow#.#qCircuitPages.currentrow# #page_title# </a> --->
<h2> #qCircuitPages.page_title#</h2>

<cftry>
<cfset oContainers.addcontainer2page(page_position=1, page_uuid="#qCircuitPages.uuid#")>

<cfset oContainers.addcontainer2page(page_position=2, page_uuid="#qCircuitPages.uuid#")>
<cfcatch type="Any">
<cfdump var = #cfcatch#>
</cfcatch>
</cftry>
<!--- <P style="page-break-after:always"></P> --->
</cfloop>

<cfif len(trim(arguments.parent))>
<cfset sParents = qCircuits.currentrow>
<cfelse>
<cfset sParents = '#arguments.parent#.#qCircuits.currentrow#'>
</cfif>

<cfset outputSection(circuit_uuid=qCircuits.uuid, parent=sParents, rootsection="false", containerPositions=arguments.containerPositions)>
<!--- <cfinvoke method="outputSection" circuit_uuid="#qCircuits.uuid#" parent="#sParents#" rootsection="false"> --->
<br class="page" />

</cfoutput>
</cffunction>

<cffunction name="outputIndex" access="public" returntype="void" hint="Prints the index of a given section" output="true" >
<cfargument name="circuit_uuid" type="string"required="yes" hint="Circuit UUID of the section to print">
<cfargument name="rootsection" default="false"required="false" hint="Whether to include the root section in the output or not">
<cfargument name="parent" type="string"required="false"default=""hint="No need to pass in anything. This is used while the function recurses.">

<cfset var qCircuits = queryNew("")>
<cfset var qCircuitPages = queryNew("")>
<cfset var sParents= "">
<cfset var oSections = application.shado_obj_factory.get("shadomx.core.sections.shado_obj_sections")>


<!--- Get the pages in the parent circuit --->
<cfif arguments.rootsection is true>

<cfset qRootCircuitPages = oSections.getSectionPages(circuit_uuid="#arguments.circuit_uuid#", exstring="$")>
<img src="/shadomx/ui/ufo/themes/blue/images/logo-white.gif" style="border:0px">

<h1>Table of Contents - #qRootCircuitPages.page_title#</h1>

<ol>
<cfloop query="qRootCircuitPages">
<cfif arguments.parent neq "">#arguments.parent#.</cfif>
<li><a name="#qRootCircuitPages.page_uuid#">#qRootCircuitPages.page_title#</a></li>
</cfloop>
</ol>
</cfif>

<!--- Get the child circuits --->
<cfset qCircuits = oSections.getSubSections(parent_circuit_uuid="#arguments.circuit_uuid#", exstring="$")>

<br/>
<cfoutput query="qCircuits">
<strong>
<cfif arguments.rootsection >Chapter</cfif>

<cfif arguments.parent neq "">#arguments.parent#.</cfif>
#qCircuits.currentrow#: #qCircuits.circuit_title#
</strong>
<br/>

<cfset qCircuitPages = oSections.getSectionPages(section_uuid="#uuid#", exstring="$")>

<!--- Get all child circuit pages --->
<cfloop query="qCircuitPages">
<cfif arguments.parent neq "">#arguments.parent#.</cfif>#qCircuits.currentrow#.#qCircuitPages.currentrow# <a name="#qCircuitPages.circuit_uuid#">#qCircuitPages.page_title#</a>
<br>
</cfloop>

<!--- create appropriate values to pass to the next round for printing. --->
<cfif len(trim(arguments.parent))>
<cfset sParent = "#qCircuits.currentrow#">
<cfelse>
<cfif len(trim(arguments.parent))>
<cfset sParent = "#arguments.parent#.#qCircuits.currentrow#">
<cfelse>
<cfset sParent = "#qCircuits.currentrow#">
</cfif>
</cfif>

<cfset outputIndex(circuit_uuid="#qCircuits.uuid#",parent="  #sParent#")>

</cfoutput>

</cffunction>

<cffunction name="getContent" access="public" output="false" returnType="string" hint="I return the content for all the pages and containers in a section">
<cfargument name="circuit_uuid" type="string"required="yes" hint="Circuit UUID of the section to print">
<cfargument name="containerPositions" type="string" required="true" hint="A comma-separated list of container positions to include in the output">
<cfargument name="rootsection" default="true"required="false" hint="Whether to include the root section in the output or not">
<cfargument name="parent" type="string"required="false"default=""hint="No need to pass in anything. This is used while the function recurses.">
<cfargument name="refresh"type="boolean"required="false"default="false"hint="If set to true, the content is generated from scratch rather than being retrieved from cache.">

<cfset var sReturn = "">
<cfset var stCache = structNew()>

<!--- Set caching params --->
<cfset stCache.key = "#arguments.circuit_uuid#-content">
<cfset stCache.scope = "Print Helper">

<!--- If we need to refresh or if the data is not in cache, then create --->
<cfif arguments.refresh OR (NOT application.shado.cacheService.inCache(key=stCache.key,scope=stCache.scope))>
<cfoutput>
<cfsavecontent variable="sReturn">
#outputSection(argumentCollection=arguments)#
</cfsavecontent>
</cfoutput>
<!--- Add to cache --->
<cfset application.shado.cacheService.putIntoCache(key=stCache.key,scope=stCache.scope, data=sReturn)>
<cfelse>
<!--- Return if found in cache --->
<cfset sReturn = application.shado.cacheService.getFromCache(key=stCache.key,scope=stCache.scope)>
</cfif>

<cfreturn sReturn>

</cffunction>

<cffunction name="getIndex" access="public" output="false" returnType="string" hint="I return a formatted index for a section being printed">
<cfargument name="circuit_uuid" type="string"required="yes" hint="Circuit UUID of the section to print">
<cfargument name="rootsection" default="true"required="false" hint="Whether to include the root section in the output or not">
<cfargument name="refresh"type="boolean"required="false"default="false"hint="If set to true, the content is generated from scratch rather than being retrieved from cache.">

<cfset var sReturn = "">
<cfset var stCache = structNew()>

<!--- Set caching params --->
<cfset stCache.key = "#arguments.circuit_uuid#-index">
<cfset stCache.scope = "Print Helper">

<!--- If we need to refresh or if the data is not in cache, then create --->
<cfif arguments.refresh OR (NOT application.shado.cacheService.inCache(key=stCache.key,scope=stCache.scope))>
<cfoutput>
<cfsavecontent variable="sReturn">
#outputIndex(argumentCollection=arguments)#
</cfsavecontent>
</cfoutput>
<!--- Add to cache --->
<cfset application.shado.cacheService.putIntoCache(key=stCache.key,scope=stCache.scope, data=sReturn)>
<cfelse>
<!--- Return if found in cache --->
<cfset sReturn = application.shado.cacheService.getFromCache(key=stCache.key,scope=stCache.scope)>
</cfif>

<cfreturn sReturn>

</cffunction>

</cfcomponent>

The component contains two methods to actually generate output: outputSection() and outputIndex().  And there are two methods that call these output functions and cache the resultant output for faster retrieval.

Create a Print Template

Second, create a ColdFusion template and save it at /yoursite/app_templates/tmp_print.cfm. Populate it with the following code. This template is used for instantiating print.cfc

<!--- This template prints a section contents to a pdf or to screen --->

<!--- Setup default values --->
<cfparam name="attributes.frmt" default="s">
<cfparam name="attributes.id" default="">
<cfparam name="stContent"default="#structNew()#">

<!--- Objects --->
<cfset oPrint = createObject("component","#request.siteContext.dsn#.app_templates.coreobjects.print")>
<cfset oUUID = application.shado_obj_factory.get("shadomx.core.shado.UUID")>

<cfif len(trim(attributes.id)) and oUUID.isSQLUUID(trim(attributes.id))>

<cfset attributes.id = trim(attributes.id)>

<!--- Save index and section content --->
<cfset stContent.index = oPrint.getIndex(circuit_uuid=attributes.id, rootsection=true)>
<cfset stContent.content = oPrint.getContent(circuit_uuid=attributes.id, containerPositions="1,2")>

<cfswitch expression="#attributes.frmt#">

<!--- PDF --->
<cfcase value="p">

<!--- this reduces the image size when going to print --->
<!--- <cfset request.printimage = true> --->
<cfset sFilePath = expandpath('/#request.sitecontext.dsn#/app_templates/print/#attributes.id#.pdf')>
<cfset oSections = application.shado_obj_factory.get("shadomx.core.sections.shado_obj_sections")>

<cfdocument format="pdf" Unit="cm" Orientation="portrait" PageType="A4" fontembed="no" margintop="2" marginbottom="2" overwrite="true" filename="#sFilePath#">

<cfset qSection = oSections.get(uuid=trim(attributes.id))>

<!--- Include print styles --->
<style>
<cfinclude template="/#request.siteContext.dsn#/app_templates/css/printdocs.css">
</style>

<cfoutput>
#stContent.index#
#stContent.content#
</cfoutput>

</cfdocument>

<CFHEADER NAME="Content-Disposition" VALUE="Inline; filename=#replace(qSection.circuit_title,' ','-','all')#.pdf">
<CFCONTENT TYPE="application/pdf" FILE="#sFilePath#" DELETEFILE="NO" RESET="FALSE">

</cfcase>

<!--- Screen printing --->
<cfdefaultcase>
<cfoutput>
#stContent.index#
#stContent.content#
</cfoutput>

</cfdefaultcase>

</cfswitch>

</cfif>

The template figures out if the user is requesting and PDF or screen output and accordingly does the neeful.

Create a Print Helper System Page

Third, create a page with the name "print" and title "Print Helper" in the System Pages in the Site Tree. Apply tmp_print.cfm template to this page. (If the template does not show up in the template drop-down, clear the variables cache -- the template list is cached for a brief duration and that causes the newly added to template to not be visible in the list.)

Code Templates to Use Print Helper

And lastly, add some code on your regular templates to call the the Print Helper to print a given page. You need to pass in two parameters when calling the Print Helper page:

  1. id: This is the circuit_uuid of the page on which the user currently is on.
  2. frmt: Format to print in. Possible options are: p (for pdf) and s (for screen)

So the code might look like the following:

<ul>
<li><a href="/print.cfm?id=#request.getpageobject.circuit_uuid#&frmt=s">Print Section</a></li>
<li><a href="/print.cfm?id=#request.getpageobject.circuit_uuid#&frmt=p">PDF</a></li>
</u>

For an example of this in action, look at the User or Developer Documentation section.


Comments

Add a comment

Excellent! I'm in need of this very thing, in the next few weeks. It will allow us to completely eliminate our enormous, expensive printed Course Handbook and provide it online instead.

# Posted by: Chris Simmons| 24 Nov 2008 | 05:44 PM


You can buy on our site pills at low cost Viagra, Cialis, Levitra, Propecia and much more. 100% QUALITY GUARANTEED. www.neededpills.com

# Posted by: Kevin Benton| 24 Jan 2009 | 11:37 PM

Add Comment